diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index ee75a1a905b08ace853e7db5c6aad84aed442151..cbe16b27a66c88f44988f60d89398cfbf6f54376 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,8 +1,3 @@ -configure_file( - "${PROJECT_SOURCE_DIR}/doc/tnt.ent.cmake" - "${PROJECT_BINARY_DIR}/doc/tnt.ent" - ) - configure_file( "${PROJECT_SOURCE_DIR}/doc/www/content/newsite/download.yml.in" "${PROJECT_BINARY_DIR}/doc/www/content/newsite/download.yml" @@ -11,7 +6,6 @@ configure_file( add_subdirectory(man) if (ENABLE_DOC) - add_subdirectory(user) add_subdirectory(sphinx) add_subdirectory(www) endif() diff --git a/doc/isopub.ent b/doc/isopub.ent deleted file mode 100644 index a11787828a38f60b2716ef56ba4c108165af4c54..0000000000000000000000000000000000000000 --- a/doc/isopub.ent +++ /dev/null @@ -1,125 +0,0 @@ - -<!-- - File isopub.ent produced by the XSL script entities.xsl - from input data in unicode.xml. - - Please report any errors to David Carlisle - via the public W3C list www-math@w3.org. - - The numeric character values assigned to each entity - (should) match the Unicode assignments in Unicode 4.0. - - Entity names in this file are derived from files carrying the - following notice: - - (C) International Organization for Standardization 1986 - Permission to copy in any form is granted for use with - conforming SGML systems and applications as defined in - ISO 8879, provided this notice is included in all copies. - ---> - - -<!-- - Version: $Id: isopub.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $ - - Public identifier: ISO 8879:1986//ENTITIES Publishing//EN//XML - System identifier: http://www.w3.org/2003/entities/iso8879/isopub.ent - - The public identifier should always be used verbatim. - The system identifier may be changed to suit local requirements. - - Typical invocation: - - <!ENTITY % isopub PUBLIC - "ISO 8879:1986//ENTITIES Publishing//EN//XML" - "http://www.w3.org/2003/entities/iso8879/isopub.ent" - > - %isopub; - ---> - -<!ENTITY blank "␣" ><!--OPEN BOX --> -<!ENTITY blk12 "▒" ><!--MEDIUM SHADE --> -<!ENTITY blk14 "░" ><!--LIGHT SHADE --> -<!ENTITY blk34 "▓" ><!--DARK SHADE --> -<!ENTITY block "█" ><!--FULL BLOCK --> -<!ENTITY bull "•" ><!--BULLET --> -<!ENTITY caret "⁁" ><!--CARET INSERTION POINT --> -<!ENTITY check "✓" ><!--CHECK MARK --> -<!ENTITY cir "○" ><!--WHITE CIRCLE --> -<!ENTITY clubs "♣" ><!--BLACK CLUB SUIT --> -<!ENTITY copysr "℗" ><!--SOUND RECORDING COPYRIGHT --> -<!ENTITY cross "✗" ><!--BALLOT X --> -<!ENTITY Dagger "‡" ><!--DOUBLE DAGGER --> -<!ENTITY dagger "†" ><!--DAGGER --> -<!ENTITY dash "‐" ><!--HYPHEN --> -<!ENTITY diams "♦" ><!--BLACK DIAMOND SUIT --> -<!ENTITY dlcrop "⌍" ><!--BOTTOM LEFT CROP --> -<!ENTITY drcrop "⌌" ><!--BOTTOM RIGHT CROP --> -<!ENTITY dtri "▿" ><!--WHITE DOWN-POINTING SMALL TRIANGLE --> -<!ENTITY dtrif "▾" ><!--BLACK DOWN-POINTING SMALL TRIANGLE --> -<!ENTITY emsp " " ><!--EM SPACE --> -<!ENTITY emsp13 " " ><!--THREE-PER-EM SPACE --> -<!ENTITY emsp14 " " ><!--FOUR-PER-EM SPACE --> -<!ENTITY ensp " " ><!--EN SPACE --> -<!ENTITY female "♀" ><!--FEMALE SIGN --> -<!ENTITY ffilig "ffi" ><!--LATIN SMALL LIGATURE FFI --> -<!ENTITY fflig "ff" ><!--LATIN SMALL LIGATURE FF --> -<!ENTITY ffllig "ffl" ><!--LATIN SMALL LIGATURE FFL --> -<!ENTITY filig "fi" ><!--LATIN SMALL LIGATURE FI --> -<!ENTITY flat "♭" ><!--MUSIC FLAT SIGN --> -<!ENTITY fllig "fl" ><!--LATIN SMALL LIGATURE FL --> -<!ENTITY frac13 "⅓" ><!--VULGAR FRACTION ONE THIRD --> -<!ENTITY frac15 "⅕" ><!--VULGAR FRACTION ONE FIFTH --> -<!ENTITY frac16 "⅙" ><!--VULGAR FRACTION ONE SIXTH --> -<!ENTITY frac23 "⅔" ><!--VULGAR FRACTION TWO THIRDS --> -<!ENTITY frac25 "⅖" ><!--VULGAR FRACTION TWO FIFTHS --> -<!ENTITY frac35 "⅗" ><!--VULGAR FRACTION THREE FIFTHS --> -<!ENTITY frac45 "⅘" ><!--VULGAR FRACTION FOUR FIFTHS --> -<!ENTITY frac56 "⅚" ><!--VULGAR FRACTION FIVE SIXTHS --> -<!ENTITY hairsp " " ><!--HAIR SPACE --> -<!ENTITY hearts "♥" ><!--BLACK HEART SUIT --> -<!ENTITY hellip "…" ><!--HORIZONTAL ELLIPSIS --> -<!ENTITY hybull "⁃" ><!--HYPHEN BULLET --> -<!ENTITY incare "℅" ><!--CARE OF --> -<!ENTITY ldquor "„" ><!--DOUBLE LOW-9 QUOTATION MARK --> -<!ENTITY lhblk "▄" ><!--LOWER HALF BLOCK --> -<!ENTITY loz "◊" ><!--LOZENGE --> -<!ENTITY lozf "⧫" ><!--BLACK LOZENGE --> -<!ENTITY lsquor "‚" ><!--SINGLE LOW-9 QUOTATION MARK --> -<!ENTITY ltri "◃" ><!--WHITE LEFT-POINTING SMALL TRIANGLE --> -<!ENTITY ltrif "◂" ><!--BLACK LEFT-POINTING SMALL TRIANGLE --> -<!ENTITY male "♂" ><!--MALE SIGN --> -<!ENTITY malt "✠" ><!--MALTESE CROSS --> -<!ENTITY marker "▮" ><!--BLACK VERTICAL RECTANGLE --> -<!ENTITY mdash "—" ><!--EM DASH --> -<!ENTITY mldr "…" ><!--HORIZONTAL ELLIPSIS --> -<!ENTITY natur "♮" ><!--MUSIC NATURAL SIGN --> -<!ENTITY ndash "–" ><!--EN DASH --> -<!ENTITY nldr "‥" ><!--TWO DOT LEADER --> -<!ENTITY numsp " " ><!--FIGURE SPACE --> -<!ENTITY phone "☎" ><!--BLACK TELEPHONE --> -<!ENTITY puncsp " " ><!--PUNCTUATION SPACE --> -<!ENTITY rdquor "”" ><!--RIGHT DOUBLE QUOTATION MARK --> -<!ENTITY rect "▭" ><!--WHITE RECTANGLE --> -<!ENTITY rsquor "’" ><!--RIGHT SINGLE QUOTATION MARK --> -<!ENTITY rtri "▹" ><!--WHITE RIGHT-POINTING SMALL TRIANGLE --> -<!ENTITY rtrif "▸" ><!--BLACK RIGHT-POINTING SMALL TRIANGLE --> -<!ENTITY rx "℞" ><!--PRESCRIPTION TAKE --> -<!ENTITY sext "✶" ><!--SIX POINTED BLACK STAR --> -<!ENTITY sharp "♯" ><!--MUSIC SHARP SIGN --> -<!ENTITY spades "♠" ><!--BLACK SPADE SUIT --> -<!ENTITY squ "□" ><!--WHITE SQUARE --> -<!ENTITY squf "▪" ><!--BLACK SMALL SQUARE --> -<!ENTITY star "☆" ><!--WHITE STAR --> -<!ENTITY starf "★" ><!--BLACK STAR --> -<!ENTITY target "⌖" ><!--POSITION INDICATOR --> -<!ENTITY telrec "⌕" ><!--TELEPHONE RECORDER --> -<!ENTITY thinsp " " ><!--THIN SPACE --> -<!ENTITY uhblk "▀" ><!--UPPER HALF BLOCK --> -<!ENTITY ulcrop "⌏" ><!--TOP LEFT CROP --> -<!ENTITY urcrop "⌎" ><!--TOP RIGHT CROP --> -<!ENTITY utri "▵" ><!--WHITE UP-POINTING SMALL TRIANGLE --> -<!ENTITY utrif "▴" ><!--BLACK UP-POINTING SMALL TRIANGLE --> -<!ENTITY vellip "⋮" ><!--VERTICAL ELLIPSIS --> diff --git a/doc/sphinx/book/index.rst b/doc/sphinx/book/index.rst index 41331fb884094a68aab7720fd167e9400964ac37..cd3e153ba22183ad74cdb0414442a86f9d1885aa 100644 --- a/doc/sphinx/book/index.rst +++ b/doc/sphinx/book/index.rst @@ -5,10 +5,10 @@ .. toctree:: intro + box/index replication configuration administration - box/index connectors/index app_a_errcodes app_b_proctitle diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 3dbc4af596728777031324e8cfa25678a4c7666b..12f415790c47c4467125aa17425cc8b184a439cc 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -8,6 +8,6 @@ intro.rst faq.rst getting_started - reference/index.rst book/index.rst + reference/index.rst dev_guide/index.rst diff --git a/doc/sql.txt b/doc/sql.txt deleted file mode 100644 index d12f229bd3da03fc597e77f9b7587f75bbb51339..0000000000000000000000000000000000000000 --- a/doc/sql.txt +++ /dev/null @@ -1,62 +0,0 @@ -; -; Tarantool SQL parser is implemented entirely on the client side. -; This BNF provides a reference of the supported subset of -; SQL, to which all clients are strongly encouraged -; to stick. -; -; Convention: UPPERCASE letters are used for terminals and literals. -; Lowercase letters are used for <non-terminals>. SQL is -; case-insensitive, so this convention is present only to improve -; legibility of the BNF. -; -; Tarantool features not supported in SQL: -; - multipart keys -; - update operations, except SET -; - all index-specific queries, such as range queries, bitset -; expression evaluation, iteration. These are only available -; in Lua. - -<sql> ::= <insert> | <replace> | <update> | <delete> | <select> - -<insert> ::= INSERT [INTO] <ident> VALUES <value_list> - -<replace> ::= REPLACE [INTO] <ident> VALUES <value_list> - -<update> ::= UPDATE <ident> SET <update_list> <simple_where> - -<delete> ::= DELETE FROM <ident> <simple_where> - -; It's only possible to select all fields of a tuple (* for field list) -<select> ::= SELECT * FROM <ident> <where> <opt_limit> - -<simple_where> ::= WHERE <predicate> - -<where> ::= WHERE <disjunction> - -<predicate> ::= <ident> = <constant> - -<disjunction> ::= <predicate> [{OR <predicate>}+] - -; LIMIT is optional -<opt_limit> ::= | LIMIT NUM[, NUM] - -<value_list> ::= (<constant> [{, <constant>}+]) - -<update_list> ::= <ident> = <constant> [{, <ident> = <constant>}+] - -<constant> ::= STR | NUM - -<ident> ::= ID - -; Only integer numbers, optionally signed, are supported -NUM ::= [+-]?[0-9]+ - -; Strings must be single-quoted -STR ::= '.*' - -; Identifiers must be standard SQL, but end with digits. -; These digits are used to infer the namespace or index id. - -ID ::= [a-z_]+[0-9]+ - -; vim: syntax=bnf diff --git a/doc/tnt.ent.cmake b/doc/tnt.ent.cmake deleted file mode 100644 index 4c14b3172c7a0b9c15f0270cf197329afd63269a..0000000000000000000000000000000000000000 --- a/doc/tnt.ent.cmake +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - This file contains all common entities. - tnt.ent is built by cmake from tnt.ent.cmake. ---> -<!ENTITY tnt_version "@PACKAGE_VERSION@"> -<!-- Include the standard ISO 8879 publishing entities --> -<!ENTITY % isopub SYSTEM "file://@CMAKE_SOURCE_DIR@/doc/isopub.ent"> -%isopub; -<!-- - vim: syntax=dtd ---> diff --git a/doc/user/CMakeLists.txt b/doc/user/CMakeLists.txt deleted file mode 100644 index 7b85402e877426ec777a6633add3a64985f88777..0000000000000000000000000000000000000000 --- a/doc/user/CMakeLists.txt +++ /dev/null @@ -1,104 +0,0 @@ -set(PATH_USERGUIDE_HTML "${PROJECT_BINARY_DIR}/doc/www/content/doc/user_guide.html") -set(PATH_USERGUIDE_HTML_CHUNK "${PROJECT_BINARY_DIR}/doc/www/content/doc/user_guide/") -set(PATH_USERGUIDE_TXT "${PROJECT_BINARY_DIR}/doc/user/tarantool_user_guide.txt") - -if (XMLLINT STREQUAL "XMLLINT-NOTFOUND") - message (FATAL_ERROR "xmllint is missing") -endif() - -if (XSLTPROC STREQUAL "XSLTPROC-NOTFOUND") - message (FATAL_ERROR "xsltproc is missing") -endif() - -if (JING STREQUAL "JING-NOTFOUND") - message (FATAL_ERROR "jing is missing") -endif() - -if (LYNX STREQUAL "LYNX-NOTFOUND") - message (FATAL_ERROR "lynx is missing") -endif() - -# XMLLINT is not able to validate SCHEMATRON constraints, and -# therefore is not a good validation tool for DocBook 5. However, -# it can validate the entire document, following xinclude -# directives, and thus is used here. To validate individual XML -# files, or for troubleshooting, I (Kostja) recommend using jing, -# since its diagnostics output is significantly more readable: -# jing http://docbook.org/xml/5.0/rng/docbookxi.rng file.xml -# -add_custom_target(doc-check - COMMAND ${XMLLINT} --xinclude --noout - --relaxng http://docbook.org/xml/5.0/rng/docbookxi.rng - ${CMAKE_SOURCE_DIR}/doc/user/user.xml) - -# -# xsltproc-based documentation generation (default) -# -add_custom_target(html - COMMAND ${XSLTPROC} --nonet --xinclude - --stringparam base.dir "${PATH_USERGUIDE_HTML_CHUNK}" - ${CMAKE_SOURCE_DIR}/doc/user/tnt-html-chunk.xsl - ${CMAKE_SOURCE_DIR}/doc/user/user.xml) - -add_custom_target(html-chunk - COMMAND ${XSLTPROC} --nonet --xinclude - -o ${PATH_USERGUIDE_HTML} - ${CMAKE_SOURCE_DIR}/doc/user/tnt-html.xsl - ${CMAKE_SOURCE_DIR}/doc/user/user.xml) - -add_custom_target(txt - DEPENDS html - COMMAND ${LYNX} -dump ${PATH_USERGUIDE_HTML} > ${PATH_USERGUIDE_TXT}) - -add_custom_target(pdf - COMMAND ${XSLTPROC} --nonet - --stringparam collect.xref.targets "all" - --xinclude -o tarantool_user_guide.fo - ${CMAKE_SOURCE_DIR}/doc/user/tnt-fo.xsl - ${CMAKE_SOURCE_DIR}/doc/user/user.xml - COMMAND fop tarantool_user_guide.fo tarantool_user_guide.pdf) - -add_custom_target(relink - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${XSLTPROC} --nonet - --stringparam collect.xref.targets "only" - --xinclude tnt-html.xsl user.xml) - -# -# Java saxon-based documentation generation (misc) -# -add_custom_target(html-saxon - COMMAND java -cp "/usr/share/java/saxon.jar:/usr/share/java/xml-resolver.jar:/usr/share/java/docbook-xsl-saxon.jar:/usr/share/java/xercesImpl.jar:/etc/xml/resolver:/usr/share/java/xslthl.jar:/usr/share/java/xml-commons-resolver-1.1.jar" - -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl - -Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl - -Dorg.apache.xerces.xni.parser.XMLParserConfiguration=org.apache.xerces.parsers.XIncludeParserConfiguration - com.icl.saxon.StyleSheet - -x org.apache.xml.resolver.tools.ResolvingXMLReader - -y org.apache.xml.resolver.tools.ResolvingXMLReader - -r org.apache.xml.resolver.tools.CatalogResolver - -u -o ${PATH_USERGUIDE_HTML} user.xml tnt-html.xsl) - -add_custom_target(html-saxon-chunk - COMMAND java -cp "/usr/share/java/saxon.jar:/usr/share/java/xml-resolver.jar:/usr/share/java/docbook-xsl-saxon.jar:/usr/share/java/xercesImpl.jar:/etc/xml/resolver:/usr/share/java/xslthl.jar:/usr/share/java/xml-commons-resolver-1.1.jar" - -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl - -Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl - -Dorg.apache.xerces.xni.parser.XMLParserConfiguration=org.apache.xerces.parsers.XIncludeParserConfiguration - com.icl.saxon.StyleSheet - -x org.apache.xml.resolver.tools.ResolvingXMLReader - -y org.apache.xml.resolver.tools.ResolvingXMLReader - -r org.apache.xml.resolver.tools.CatalogResolver - -u user.xml tnt-html-chunk.xsl - base.dir="${PATH_USERGUIDE_HTML_CHUNK}") - - -add_custom_target(pdf-saxon - COMMAND java -cp "/usr/share/java/saxon.jar:/usr/share/java/xml-commons-resolver-1.1.jar:/usr/share/java/docbook-xsl-saxon.jar:/usr/share/java/xercesImpl.jar:/etc/xml/resolver:/usr/share/java/xslthl.jar" - -Djavax.xml.parsers.DocumentBuilderFactory=org.apache.xerces.jaxp.DocumentBuilderFactoryImpl - -Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl - -Dorg.apache.xerces.xni.parser.XMLParserConfiguration=org.apache.xerces.parsers.XIncludeParserConfiguration - com.icl.saxon.StyleSheet - -x org.apache.xml.resolver.tools.ResolvingXMLReader - -y org.apache.xml.resolver.tools.ResolvingXMLReader - -r org.apache.xml.resolver.tools.CatalogResolver - -u -o tarantool_user_guide.fo user.xml tnt-fo.xsl - COMMAND fop tarantool_user_guide.fo tarantool_user_guide.pdf) diff --git a/doc/user/configuration-reference.xml b/doc/user/configuration-reference.xml deleted file mode 100644 index f7cd99e82a78242d2306b5397cb5435b810e93c8..0000000000000000000000000000000000000000 --- a/doc/user/configuration-reference.xml +++ /dev/null @@ -1,768 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xi="http://www.w3.org/2001/XInclude" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="configuration-reference"> - -<title>Configuration reference</title> -<blockquote><para> - This chapter provides a reference of options which - can be set on the command line or in an initialization file. -</para></blockquote> - -<para> -Tarantool is started by entering the command: - -<programlisting><prompt>$ </prompt><userinput>tarantool</userinput></programlisting> -or -<programlisting><prompt>$ </prompt><userinput>tarantool <replaceable>options</replaceable></userinput></programlisting> -or -<programlisting><prompt>$ </prompt><userinput>tarantool <replaceable>Lua-initialization-file</replaceable> [<replaceable>arguments</replaceable>]</userinput></programlisting> - -</para> - -<section xml:id="command-line-options"> -<title>Command options</title> - <para> - - </para> - <itemizedlist> - <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> - </listitem> - - <listitem xml:id="version-option"> - <para><option>--version</option>, <option>-V</option></para> - <para>Print product name and version, for example: - <programlisting><prompt>$ </prompt> <userinput>./tarantool --version</userinput> -Tarantool 1.6.3-439-g7e1011b -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> - The 3-number version follows the standard - <literal><major>-<minor>-<patch></literal> - scheme, in which <literal><major></literal> number - is changed only rarely, <literal><minor></literal> - is incremented for each new milestone and - indicates possible incompatible changes, - and <literal><patch></literal> stands for the number of - bug fix releases made after the start of the - milestone. The optional commit number and - commit SHA1 are output for non-released versions - 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> - Tarantool uses <link - xlink:href="http://www.kernel.org/pub/software/scm/git/docs/git-describe.html">git describe</link> to produce its version id, and - this id can be used at any time to check out the - corresponding source from our <link - xlink:href="git://github.com/tarantool/tarantool.git">git repository</link>. - </para></note> - </listitem> - - </itemizedlist> - -</section> - - -<section xml:id="URI" xreflabel="URI"> - <title>URI</title> - <para> -Some configuration parameters and some functions -depend on a URI, or "Universal Resource Identifier". -The URI string format is similar to the -<link -xlink:href="http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax">generic syntax for a URI schema</link>. -So it may contain (in order) a user name for login, a password, -a host name or host IP address, and a port number. -Only the port number is always mandatory. The password -is mandatory if the user name is specified, -unless the user name is 'guest'. -So, formally, the URI syntax is -<code>[host:]port</code> -or <code>[username:password@]host:port</code> -or if username='guest' it may be -<code>[username@]host:port</code>. -If host is omitted, then 'localhost' is assumed. -If username:password is omitted, then 'guest' is assumed. -Some examples: - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry>URI fragment</entry><entry>Example</entry></row> - </thead> - <tbody> - <row><entry>port</entry><entry> 3301</entry></row> - <row><entry>host:port</entry><entry> 127.0.0.1:3301</entry></row> - <row><entry>guest@host:port</entry><entry> guest@mail.ru:3301</entry></row> - <row><entry>username:password@host:port</entry><entry> guest:sesame@mail.ru:3301</entry></row> - </tbody> - </tgroup> - </informaltable> -In certain circumstances a Unix socket may be used where a URI is required. -</para> -</section> - - -<section xml:id="initialization-file" xreflabel="initialization file"> -<title>Initialization file</title> -<para> -If the command to start Tarantool includes <option><replaceable>lua-initialization-file</replaceable></option>, -then Tarantool begins by invoking the Lua program in the file, -which by convention may have the name <filename>"script.lua"</filename>. - -The Lua program may get further arguments from the command line -or may use operating-system functions, such as getenv(). -The Lua program almost always begins by invoking <code>box.cfg()</code>, -if the database server will be used or if ports need to be opened. -For example, suppose <filename>script.lua</filename> contains the lines<programlisting>#!/usr/bin/env tarantool -box.cfg{ - listen = os.getenv("LISTEN_URI"), - slab_alloc_arena = 0.1, - pid_file = "tarantool.pid", - rows_per_wal = 50 -} -print('Starting ',arg[1])</programlisting> -and suppose the command line is <code>~/tarantool/src/tarantool script.lua ARG</code>. -Then the screen might look like this:<programlisting> -<prompt>$</prompt> <userinput>export LISTEN_URI=3301</userinput> -<prompt>$</prompt> <userinput>~/tarantool/src/tarantool script.lua ARG</userinput> -... main/101/script.lua C> version 1.6.3-439-g7e1011b -... main/101/script.lua C> log level 5 -... main/101/script.lua I> mapping 107374184 bytes for a shared arena... -... main/101/spawner C> initialized -... main/101/script.lua I> recovery start -... main/101/script.lua I> recovering from `./00000000000000000000.snap' -... main/101/script.lua I> primary: bound to 0.0.0.0:3301 -... main/102/leave_local_hot_standby I> ready to accept requests -Starting ARG -... main C> entering the event loop</programlisting> -</para> -</section> - -<section xml:id="configuration-parameters" xreflabel="configuration parameters"> -<title>Configuration parameters</title> -<para> - Configuration parameters have the form - <code>box.cfg{<replaceable> key = value [, key = value ...]</replaceable>}</code>. - Since box.cfg may contain many configuration parameters - and since some of the parameters (such as directory addresses) - are semi-permanent, it's best to keep box.cfg in a Lua file. - Typically this Lua file is the initialization file - which is specified on the tarantool command line. - </para> - <para> - 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> - To see all the non-null parameters, say <code>box.cfg</code> (no parentheses). - To see a particular parameter, for example the listen address, say <code>box.cfg.listen</code>. - </para> - <para> - The following tables describe all parameters for basic operation, - for storage, for binary logging and snapshots, for replication, - for networking, and for logging. - </para> - - <table frame='all' pgwide='1'> - <title>Basic parameters</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>username</entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry>UNIX user name to switch to after start.</entry> - </row> - - <row> - <entry xml:id="work_dir" xreflabel="work_dir">work_dir</entry> - <entry>string</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 - start. Can be relative to the current directory. - If not specified, defaults to the current directory.</entry> - </row> - - <row> - <entry xml:id="wal_dir" xreflabel="wal_dir">wal_dir</entry> - <entry>string</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 - that snapshot files and write-ahead log files - can be stored on separate disks. - If not specified, defaults to work_dir.</entry> - </row> - - <row> - <entry xml:id="snap_dir" xreflabel="snap_dir">snap_dir</entry> - <entry>string</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 xml:id="sophia_dir" xreflabel="sophia_dir">sophia_dir</entry> - <entry>string</entry> - <entry>"sophia"</entry> - <entry>no</entry> - <entry>A directory where sophia files will be stored. Can be - relative to work_dir. If not specified, defaults to - work_dir/sophia.</entry> - </row> - - <row> - <entry xml:id="core-dump" xreflabel="core-dump">coredump</entry> - <entry>boolean</entry> - <entry>false</entry> - <entry>no</entry> - <entry>Deprecated. Do not use.</entry> - </row> - <row> - <entry xml:id="primary_port" xreflabel="primary_port">listen</entry> - <entry>integer or string</entry> - <entry>null</entry> - <entry>yes</entry> - <entry>The read/write data port number or <link linkend="URI">URI</link> (Universal Resource Identifier) string. - Has no default value, so <emphasis - role="strong">must be specified</emphasis> - if connections will occur from remote clients - that do not use "admin address" (the administrative host and port). - Note: a replica also binds to this port, and accepts - connections, but these connections can only serve - reads until the replica becomes a master. - A typical value is 3301. - The listen parameter may also be set for <olink targetptr="local_hot_standby">local hot standby</olink>.</entry> - </row> - - <row> - <entry>pid_file</entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry>Store the process id in this file. Can be - relative to work_dir. A typical value is "tarantool.pid".</entry> - </row> - - <row> - <entry xml:id="custom_proc_title" - xreflabel="custom_proc_title"> - custom_proc_title - </entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry> - <para>Inject the given string into <olink - targetptr="proctitle">server process title</olink> - (what's shown in the COMMAND column for <command>ps</command> - and <command>top</command> commands). For example, - ordinarily <command>ps</command> shows the Tarantool server process thus: - </para><programlisting><prompt>$</prompt> <userinput>ps -ef | grep tarantool</userinput> -1000 22364 2778 0 09:14 pts/0 00:00:00 tarantool: running -1000 22394 22364 0 09:14 pts/0 00:00:00 tarantool: spawner -tarantool: primary pri: 3301 adm: 3313</programlisting> - <para>But if the configuration parameters include custom_proc_title='sessions' then - the output looks like:</para> -<programlisting><prompt>$</prompt> <userinput>ps -ef | grep tarantool</userinput> -1000 22364 2778 0 09:14 pts/0 00:00:00 tarantool: running@sessions -1000 22394 22364 0 09:14 pts/0 00:00:00 tarantool: spawner@sessions -tarantool: primary pri: 3301 adm: 3313</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='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>slab_alloc_arena</entry> - <entry>float</entry> - <entry>1.0</entry> - <entry>no</entry> - <entry> - <anchor xml:id="slab_alloc_arena" xreflabel="slab_alloc_arena"/> - How much memory Tarantool - allocates to actually - store tuples, <emphasis role="strong">in - gigabytes</emphasis>. When the limit is reached, INSERT - or UPDATE requests begin failing with error - <olink targetptr="ER_MEMORY_ISSUE"/>. - While the server does not go - beyond the defined limit to allocate tuples, there is - additional memory used to store indexes and connection - information. Depending on actual configuration and - workload, Tarantool can consume up to 20% more than the - limit set here.</entry> - </row> - - <row> - <entry>slab_alloc_minimal</entry> - <entry>integer</entry> - <entry>64</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> - - <row> - <entry>slab_alloc_factor</entry> - <entry>float</entry> - <entry>2.0</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 - memory depending on the total amount of memory available - and the distribution of item sizes.</entry> - </row> - - <row> - <entry>sophia</entry> - <entry>table</entry> - <entry>(see the note)</entry> - <entry>no</entry> - <entry>The default sophia configuration can be changed with - sophia={page_size=<replaceable>number</replaceable>, threads=<replaceable>number</replaceable>, - node_size=<replaceable>number</replaceable>, memory_limit=<replaceable>number</replaceable> }. - This method may change in the future.</entry> - </row> - - </tbody> - </tgroup> - </table> - - - <table xml:id="snapshot-daemon" frame='all' pgwide='1'> - <title>Snapshot daemon</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>snapshot_period</entry> - <entry>float</entry> - <entry>0</entry> - <entry>yes</entry> - <entry> - The interval between actions by the snapshot daemon, in seconds. - The snapshot daemon is a fiber which is constantly running. - If snapshot_period is set to a value greater than zero, - then the snapshot daemon - will call <olink targetptr="box.snapshot"/> every snapshot_period seconds, creating - a new snapshot file each time. - For example, <code>box.cfg{snapshot_period=3600}</code> - will cause the snapshot daemon to create a new database - snapshot once per hour. - </entry> - </row> - - <row> - <entry>snapshot_count</entry> - <entry>float</entry> - <entry>6</entry> - <entry>yes</entry> - <entry> - <para> - The maximum number of snapshots that the snapshot daemon maintains. - For example, <code>box.cfg{snapshot_period=3600, snapshot_count=10}</code> - will cause the snapshot daemon - to create a new snapshot each hour until it has created - ten snapshots. After that, it will remove the oldest - snapshot (and any associated write-ahead-log files) after creating - a new one. If snapshot_count equals zero, then the snapshot - daemon does not remove old snapshots. - </para> - </entry> - </row> - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Binary logging and snapshots</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>panic_on_snap_error</entry> - <entry>boolean</entry> - <entry>true</entry> - <entry>no</entry> - <entry>If there is an error while reading the snapshot file (at - server start), abort.</entry> - </row> - - <row> - <entry>panic_on_wal_error</entry> - <entry>boolean</entry> - <entry>false</entry> - <entry>no</entry> - <entry>If there is an error while reading a write-ahead - log file (at server start), abort.</entry> - </row> - - <row> - <entry xml:id="rows_per_wal" xreflabel="rows_per_wal">rows_per_wal</entry> - <entry>integer</entry> - <entry>500000</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 - <filename><first-lsn-in-wal>.xlog</filename> - This can be useful for simple rsync-based backups. - </entry> - </row> - - <row> - <entry>snap_io_rate_limit</entry> - <entry>float</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 - how many megabytes per second it can write to disk. - The same can be achieved by splitting <olink - targetptr="wal_dir"/> and <olink targetptr="snap_dir"/> - locations and moving snapshots to a separate disk.</entry> - </row> - - <row> - <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); - </entry> - </row> - - <row> - <entry xml:id="wal_dir_rescan_delay" xreflabel="wal_dir_rescan_delay">wal_dir_rescan_delay</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> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Replication</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry xml:id="replication_source" - xreflabel="replication_source">replication_source</entry> - <entry>string</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. - The replica server will try to connect to the master - which replication_source specifies with a <link linkend="URI">URI</link> (Universal Resource Identifier), - for example 'konstantin:secret_password@tarantool.org:3301'. - The default user name is 'guest'. - A replica server does not accept data-change requests - on the <olink targetptr="primary_port">listen</olink> port. - The replication_source parameter is - dynamic, that is, to enter master mode, simply set - replication_source to an empty string and issue - "box.cfg{replication_source=new-value}".</entry> - </row> - - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Networking</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>io_collect_interval</entry> - <entry>float</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 - number of client connections is large, but requests are - not so frequent (for example, each connection issues - just a handful of requests per second). </entry> - </row> - - <row> - <entry>readahead</entry> - <entry>integer</entry> - <entry>16320</entry> - <entry>yes</entry> - <entry>The size of the read-ahead buffer associated with a - client connection. The larger the buffer, the more - memory an active connection consumes and the more requests - can be read from the operating system buffer in a single - system call. The rule of thumb is to make sure the buffer - can contain at least a few dozen requests. Therefore, if - a typical tuple in a request is large, e.g. a few - kilobytes or even megabytes, the read-ahead buffer size should - be increased. If batched request processing is not - used, it's prudent to leave this setting at its - default.</entry> - </row> - - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Logging</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry xml:id="log_level" xreflabel="log_level">log_level</entry> - <entry>integer</entry> - <entry>5</entry> - <entry><emphasis role="strong">yes</emphasis></entry> - <entry>How verbose the logging is. There are six log - verbosity classes: 1 -- SYSERROR, 2 -- ERROR, 3 -- CRITICAL, 4 -- - WARNING, 5 -- INFO, 6 -- DEBUG. By setting log_level, - one can enable logging of all classes below or equal - to the given level. Tarantool prints its logs to the - standard error stream by default, but this can be - changed with the "logger" configuration parameter. - </entry> - </row> - - <row> - <entry xml:id="logger" xreflabel="logger">logger</entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry>By default, the log is sent to the standard - error stream (<filename>stderr</filename>). If logger - is specified, the log is sent to the file named in the string. - Example setting: logger = 'tarantool.log' - (this will open tarantool.log for output on the - server's default directory). - </entry> - </row> - - <row> - <entry>logger_nonblock</entry> - <entry>boolean</entry> - <entry>true</entry> - <entry>no</entry> - <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 true may improve logging - performance at the cost of some log messages getting - lost.</entry> - </row> - - <row> - <entry>too_long_threshold</entry> - <entry>float</entry> - <entry>0.5</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. - Has effect only if log_level is less than or equal to 4 - (WARNING).</entry> - </row> - - </tbody> - </tgroup> - </table> - -</section> - -<section xml:id="local_hot_standby" xreflabel="local_hot_standby"> -<title>Local hot standby</title> - - <para> - Local hot standby is a feature which provides a simple form of failover without replication. - To initiate it, start a second instance of the Tarantool server on the same computer with - the same <code>box.cfg</code> configuration settings -- including the same directories and same URIs. - A warning should appear with a message like - "W> primary: [URI] is already in use, will retry binding after [n] seconds". - This is fine. - It means that the second instance is ready to take over if the first instance goes down. - </para> - <para> - The expectation is that there will be two - instances of the server using the same configuration. - The first one to start will be the "primary" instance. - The second one to start will be the "standby" instance. - The standby instance will initialize and will try to connect on listen - address and admin address, but will fail because the - primary instance has already taken them. - So the standby instance goes into a loop, reading the write - ahead log which the primary instance is writing (so the - two instances are always in synch), and trying to connect on the - ports. If the primary instance goes down for any reason, - the ports will become free so the standby instance will - succeed in connecting, and will become the primary instance. - Thus there is no noticeable downtime if the primary instance goes down. - </para> - <para> - If this local_hot_standby feature is being used, then replication_source should be an - empty string and wal_mode should not be equal to "none". - </para> - -</section> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/connectors.xml b/doc/user/connectors.xml deleted file mode 100644 index 8ea70b93560bb0575a4711ed3111a57ac3c37d1c..0000000000000000000000000000000000000000 --- a/doc/user/connectors.xml +++ /dev/null @@ -1,326 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="connectors"> - -<title>Connectors</title> -<blockquote><para> - This chapter documents APIs for various programming languages. -</para></blockquote> - -<section xml:id="protocol"> - <title>Protocol</title> - <para>Tarantool protocol was designed with focus on asynchronous - I/O and easy integration with proxies. Each client - request starts with a variable-length binary header, containing - request id, request type, server id, log sequence number, and - so on. - </para> - - <para> - The mandatory length, present in request header simplifies - client or proxy I/O. A response to a request is sent to the - client as soon as it is ready. It always carries in its header - the same type and id as in the request. The id makes it - possible to match a request to a response, even if the latter - arrived out of order. - </para> - - <para>Unless implementing a client driver, one needn't - concern oneself with the complications of the binary - protocol. <olink targetptr="connectors">Language-specific - drivers</olink> provide a friendly way to store domain - language data structures in Tarantool. - A complete description of the binary protocol - is maintained in annotated Backus-Naur - form in the source tree: please see - <link xlink:href="http://tarantool.org/doc/box-protocol.html"><filename>doc/box-protocol.html</filename></link>. - </para> -</section> - -<section xml:id="connector-packet-example"> -<title>Packet example</title> -<para> -The Tarantool API exists so that a client program can send a request packet -to the server, and receive a response. Here is an example of a what the client - would send for <command>box.space[513]:insert{'A', 'BB'}</command>. The BNF description of the components -is in file <link xlink:href="http://tarantool.org/doc/box-protocol.html" xlink:title="A complete BNF of Tarantool client/server protocol">doc/box-protocol.html</link>. - A third-party contribution written in Lua for unpacking Tarantool messages is in file - <link xlink:href="https://github.com/negram/Tnt-dissector/blob/master/tarantool.dis.lua" xlink:title="tarantool.dis.lua">Tnt-dissector</link>. - -</para> - <informaltable frame='topbot'> - <tgroup cols='5' align='left' colsep='1' rowsep='1'> - <colspec colname='c1'/> - <colspec colname='c2'/> - <colspec colname='c3'/> - <colspec colname='c4'/> - <colspec colname='c5'/> - <thead> - <row> - <entry>Component</entry> - <entry>Byte#0</entry> - <entry>Byte#1</entry> - <entry>Byte#2</entry> - <entry>Byte#3</entry> - </row> - </thead> - <tbody> - <row> - <entry>code for insert</entry> - <entry>2</entry> - </row> - <row> - <entry>rest of header</entry> - <entry>...</entry> - <entry>...</entry> - <entry>...</entry> - <entry>...</entry> - </row> - <row> - <entry>2-digit number: space id</entry> - <entry>cd</entry> - <entry>02</entry> - <entry>01</entry> - </row> - <row> - <entry>code for tuple</entry> - <entry>21</entry> - </row> - <row> - <entry>1-digit number: field count = 2</entry> - <entry>92</entry> - </row> - <row> - <entry>1-character string: field[1]</entry> - <entry>a1</entry> - <entry>41</entry> - </row> - <row> - <entry>2-character string: field[2]</entry> - <entry>a2</entry> - <entry>42</entry> - <entry>42</entry> - </row> - </tbody> - </tgroup> - </informaltable> -<para> -Now, one could send that packet to the tarantool server, -and interpret the response (doc/box-protocol.html has a description -of the packet format for responses as well as requests). -But it would be easier, and less error-prone, if one could -invoke a routine that formats the packet according to typed -parameters. Something like <code>response=tarantool_routine("insert",0,"A","B");</code>. -And that is why APIs exist for drivers for Perl, Python, PHP, and so on. -</para> - </section> - - <section xml:id="connector-server"> - <title>Setting up the server for connector examples</title> - <para> - This chapter has examples that show how to connect to the Tarantool - server via the Perl, PHP, and Python connectors. - The examples contain hard code that will work if and only if - the server (tarantool) is running on localhost (127.0.0.1) and is listening on port 3301 - (<code>box.cfg.listen='3301'</code>) and space 'examples' has id = 999 - (<code>box.space.tester.id = 999</code>), and - space 'examples' has a primary-key index for a numeric field - (<code>box.space[999].index[0].parts[1].type = "NUM"</code>) - and user 'guest' has privileges for reading and writing. - </para> - <para> - It is easy to meet all the conditions by starting the - server and executing this script:<programlisting> -box.cfg{listen=3301} -box.schema.space.create('examples',{id=999}) -box.space.examples:create_index('primary', {type = 'hash', parts = {1, 'NUM'}}) -box.schema.user.grant('guest','read,write','space','examples') -box.schema.user.grant('guest','read','space','_space') -</programlisting> - </para> - </section> - - <section xml:id="connector-java"> - <title>Java</title> - <para> - Please see <link xlink:href="http://dgreenru.github.io/tarantool-java/"><filename>http://dgreenru.github.io/tarantool-java/</filename></link>. - </para> - </section> - - <section xml:id="connector-go"> - <title>Go</title> - <para> - Please see <link xlink:href="https://github.com/mialinx/go-tarantool-1.6"><filename>https://github.com/mialinx/go-tarantool-1.6</filename></link>. - </para> - </section> - - <section xml:id="connector-perl"> - <title>Perl</title> - <para> - The most commonly used Perl driver is <link xlink:href='http://search.cpan.org/~unera/DR-Tarantool/'>DR::Tarantool</link>. - It is not supplied as part of the Tarantool repository; it must be installed separately. - The most common way to install it is with <link xlink:href='https://en.wikipedia.org/wiki/Cpan'>CPAN, the Comprehensive Perl Archive Network</link>. - DR::Tarantool requires other modules which should be installed first. - For example, on Ubuntu, the installation could look like this:<programlisting> -sudo cpan install AnyEvent -sudo cpan install Devel::GlobalDestruction -sudo cpan install Coro -sudo cpan install Test::Pod -sudo cpan install Test::Spelling -sudo cpan install PAR::Dist -sudo cpan install List::MoreUtils -sudo cpan install DR::Tarantool</programlisting> - </para> - <para> - Here is a complete Perl program that inserts [99999,'BB'] into space[999] via the Perl API. - Before trying to run, check that the server is listening and that <code>examples</code> exists, - as described <link linkend="connector-server">earlier</link>. - To run, paste the code into a file named example.pl and say <code>perl example.pl</code>. - The program will connect using an application-specific definition of the space. - The program will open a socket connection - with the tarantool server at localhost:3301, then send an INSERT request, - then — if all is well — end without displaying any messages. - If tarantool is not running on localhost with listen address = 3301, the program will print - <quote>Connection refused</quote>. - </para> - <para> - <programlisting language="perl"> -#!/usr/bin/perl -use DR::Tarantool ':constant', 'tarantool'; -use DR::Tarantool ':all'; -use DR::Tarantool::MsgPack::SyncClient; - -my $tnt = DR::Tarantool::MsgPack::SyncClient->connect( - host => '127.0.0.1', # look for tarantool on localhost - port => 3301, # assume tarantool listen address = default - user => 'guest', # username. one could also say 'password=>...' - - spaces => { - 999 => { # definition of space[999] ... - name => 'examples', # space[999] name = 'examples' - default_type => 'STR', # space[999] field type is 'STR' if undefined - fields => [ { # definition of space[512].fields ... - name => 'field1', type => 'NUM' } ], # space[999].field[1] name='field1',type='NUM' - indexes => { # definition of space[999] indexes ... - 0 => { - name => 'primary', fields => [ 'field1' ] } } } } ); - -$tnt->insert('tester' => [ 99999, 'BB' ]);</programlisting> - </para> - <para> - The example program only shows one command and does not show all that's necessary for - good practice. For that, please see - <link xlink:href='http://search.cpan.org/~unera/DR-Tarantool/'>DR::Tarantool CPAN repository</link>. - </para> - </section> - - <section xml:id="connector-php"> - <title>PHP</title> - - <para> - The PHP driver is <link xlink:href='https://github.com/tarantool/tarantool-php'>tarantool-php</link>. - It is not supplied as part of the Tarantool repository; it must be installed separately. - It can be installed with git. - It requires other modules which should be installed first. - For example, on Ubuntu, the installation could look like this: - <programlisting> -sudo apt-get install php5-cli -sudo apt-get install php5-dev -sudo apt-get install php-pear -cd ~ -git clone https://github.com/tarantool/tarantool-php.git -cd tarantool-php -phpize -./configure -make -#make install is optional</programlisting> - </para> - <para> - At this point there is a file named <filename>~/tarantool-php/modules/tarantool.so</filename>. - PHP will only find it if the PHP initialization file <filename>php.ini</filename> contains a line like - <code>extension=./tarantool.so</code>. - So copy <filename>tarantool.so</filename> to the working directory and tell PHP where - to find the <filename>php.ini</filename> file that contains that line ... - <programlisting> -cd ~ -cp ./tarantool-php/modules/tarantool.so . -export PHP_INI_SCAN_DIR=~/tarantool-php/tests/shared</programlisting> - </para> - <para> - Here is a complete PHP program that inserts [99999,'BB'] into a space named 'examples' via the PHP API. - Before trying to run, check that the server is listening and that <code>examples</code> exists, - as described <link linkend="connector-server">earlier</link>. - To run, paste the code into a file named example.php and say <code>php example.php</code>. - The program will open a socket connection - with the tarantool server at localhost:3301, then send an INSERT request, - then — if all is well — print "Insert succeeded". - If the tuple already exists, the program will print <quote>Duplicate key exists in unique index 0</quote>. - </para> - <para> - <programlisting> -<?php -$tarantool = new Tarantool("localhost", 3301); -try { - $tarantool->insert("examples", array(99999, "BB")); - print "Insert succeeded\n"; - } -catch (Exception $e) { - echo "Exception: ", $e->getMessage(), "\n"; - } -?></programlisting> - </para> - <para> - After running the example, it is good practice to delete the file ./tarantool.so, - since it is only compatible with PHP and its existence could confuse non-PHP applications. - </para> - <para> - The example program only shows one command and does not show all that's necessary for - good practice. For that, please see - <link - xlink:href="https://github.com/tarantool/tarantool-php/"><filename>tarantool-php</filename></link> project at GitHub. - </para> - </section> - - <section xml:id="connector-python"> - <title>Python</title> - <para> - Here is a complete Python program that inserts [99999,'Value','Value'] into space <code>examples</code> via the high-level Python API. - </para> -<programlisting language="python"> -#!/usr/bin/python -from tarantool import Connection - -c = Connection("127.0.0.1", 3301) -result = c.insert("examples",(99999,'Value', 'Value')) -print result -</programlisting> - <para> - To prepare, paste the code into a file named example.py and install tarantool-python with either - <userinput><code>pip install tarantool\>0.4</code></userinput> to install in <filename>/usr</filename> (requires root privilege) - or - <userinput><code>pip install tarantool\>0.4 --user</code></userinput> to install in <filename>~</filename> i.e. user's default directory. - Before trying to run, check that the server is listening and that <code>examples</code> exists, - as described <link linkend="connector-server">earlier</link>. - To run the program, say <code>python example.py</code>. - The program will connect to the server, will send the request, and will not throw an exception if all went well. - If the tuple already exists, the program will throw DatabaseException(“Duplicate key exists in unique indexâ€). - </para> - <para> - The example program only shows one request and does not show all that's necessary for - good practice. For that, see - <link xlink:href="http://github.com/tarantool/tarantool-python"><filename>http://github.com/tarantool/tarantool-python</filename></link>. - For an example of a Python API for <link xlink:href="https://github.com/tarantool/queue">Queue managers on Tarantool</link>, see - <link xlink:href="https://github.com/tarantool/tarantool-queue-python"><filename>https://github.com/tarantool/tarantool-queue-python</filename></link>. - </para> - </section> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/data-and-persistence.xml b/doc/user/data-and-persistence.xml deleted file mode 100644 index 99f05c566547bddae6480f6eb6d15198ba4f73a2..0000000000000000000000000000000000000000 --- a/doc/user/data-and-persistence.xml +++ /dev/null @@ -1,22 +0,0 @@ -<!DOCTYPE chapter [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:xi="http://www.w3.org/2001/XInclude" - xml:id="data-and-persistence"> -<title>Data model and data persistence</title> -<blockquote><para> - This chapter describes how Tarantool stores - values and what operations with data it supports. -</para></blockquote> - -<xi:include href="data-model.xml"/> -<xi:include href="persistence-architecture.xml"/> - -</chapter> -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/data-model.xml b/doc/user/data-model.xml deleted file mode 100644 index be1f1fc43a31a3d1925a0f6c6bb5e245c7efb341..0000000000000000000000000000000000000000 --- a/doc/user/data-model.xml +++ /dev/null @@ -1,344 +0,0 @@ - -<section xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="dynamic-data-model"> - -<title>Dynamic data model</title> - -<para> - -If you tried out the <link linkend="getting-started-start-stop"><quote>Starting Tarantool and making your first database</quote></link> -exercise from the last chapter, then your database looks like this: -<programlisting> -+--------------------------------------------+ -| | -| SPACE 'tester' | -| +----------------------------------------+ | -| | | | -| | TUPLE SET 'tester' | | -| | +-----------------------------------+ | | -| | | Tuple: [ 1 ] | | | -| | | Tuple: [ 2, 'Music' ] | | | -| | | Tuple: [ 3, 'length', 93 ] | | | -| | +-----------------------------------+ | | -| | | | -| | INDEX 'primary' | | -| | +-----------------------------------+ | | -| | | Key: 1 | | | -| | | Key: 2 | | | -| | | Key: 3 | | | -| | +-----------------------------------+ | | -| | | | -| +----------------------------------------+ | -+--------------------------------------------+ -</programlisting> -</para> - -<bridgehead renderas="sect2">Space</bridgehead> - -<para> -A <emphasis>space<alt>the paradigm of tuples and spaces is -derived from distributed computing</alt></emphasis> -- 'tester' in the example -- is a container. -</para> -<para> -When Tarantool is being used to store data, there is always at least one space. -There can be many spaces. -Each space has a unique name specified by the user. -Each space has a unique numeric identifier which can be specified by the user but usually is assigned automatically by Tarantool. -Spaces always contain one tuple set and one or more indexes. -</para> - -<bridgehead renderas="sect2">Tuple Set</bridgehead> - -<para> -A <emphasis>tuple set<alt>There's a Wikipedia article about tuples: https://en.wikipedia.org/wiki/Tuple</alt></emphasis> -- 'tester' in the example -- is a group of tuples. -</para> -<para> -There is always one tuple set in a space. -The identifier of a tuple set is the same as the space name -- 'tester' in the example. -</para> -<para> -A tuple fills -the same role as a <quote>row</quote> or a <quote>record</quote>, and the -components of a tuple (which we call <quote>fields</quote>) -fill the same role as a -<quote>row column</quote> or <quote>record field</quote>, except that: the -fields of a tuple don't need to have names. -That's why there was no need to pre-define the -tuple set when creating the space, and that's -why each tuple can have a different number of -elements, and that's why we say that Tarantool has -a <quote>dynamic</quote> data model. -Tuples are stored as <link xlink:href="http://en.wikipedia.org/wiki/MessagePack">MsgPack</link> arrays. -</para> -<para> -Any given tuple may have any number of fields and the -fields may have a variety of types. -The identifier of a field is the field's number, base 1. -For example <quote>1</quote> can be used in some contexts -to refer to the first field of a tuple. -</para> -<para> -When Tarantool returns a tuple value, it surrounds -strings with single quotes, separates fields with commas, -and encloses the tuple inside square brackets. For example: -<computeroutput>[ 3, 'length', 93 ]</computeroutput>. -</para> - -<bridgehead renderas="sect2">Index</bridgehead> - -<para xml:id="an-index"> -An index -- 'primary' in the example -- is a group of key values and pointers. -</para> -<para> -In order for a tuple set to be useful, there must always at least one index in a space. -There can be many. -As with spaces, the user can and should specify the index name, and -let Tarantool come up with a unique numeric identifier (the "index id"). -In our example there is one index and its name is <quote>primary</quote>. -</para> - -<para> -An index may be <emphasis>multi-part</emphasis>, that is, the user can declare -that an index key value is taken from two or more fields -in the tuple, in any order. An index may be <emphasis>unique</emphasis>, that is, the user can declare -that it would be illegal to have the same key value twice. -An index may have <emphasis>one of four types</emphasis>: -HASH which is fastest and uses the least memory but must be unique, -TREE which allows partial-key searching and ordered results, -BITSET which can be good for searches that contain '=' and -multiple ANDed conditions, and RTREE for spatial coordinates. -The first index is called the <emphasis><quote>primary key</quote> index</emphasis> -and it must be unique; all other indexes are called -<quote>secondary</quote> indexes. -</para> - -<para> -An index definition may include identifiers of tuple fields and their expected types. -The allowed types are NUM (64-bit unsigned integer between 0 and 18,446,744,073,709,551,615), or STR (string, any sequence of octets), -or ARRAY (a series of numbers for use with <link linkend="RTREE">RTREE indexes</link>). -Take our example, which has the request: -<programlisting>i = s:create_index('primary', {type = 'hash', parts = {1, 'NUM'}})</programlisting> -The effect is that, for all tuples in tester, field number 1 -must exist and must be a 64-bit unsigned integer. -</para> - -<para> -Space definitions and index definitions are stored permanently in <emphasis>system spaces</emphasis>. -It is possible to add, drop, or alter the definitions at runtime, with some restrictions. -The syntax details for defining spaces and indexes are in section -<link linkend="sp-box-library">The box library</link>. -</para> - -<bridgehead renderas="sect2">Data types</bridgehead> - - <para> - Tarantool can work with numbers, strings, booleans, tables, and userdata. - </para> - - <para> - <informaltable> - <tgroup cols="4" align="left" colsep="1" rowsep="1"> - <thead> - <row><entry>General type</entry> <entry>Specific type</entry><entry>What Lua type() would return</entry> <entry>Example</entry></row> - </thead> - <tbody> - <row><entry xml:id="function-type-number">scalar </entry><entry>number</entry> <entry><link xlink:href="http://www.lua.org/pil/2.3.html">"number"</link></entry> <entry>12345</entry></row> - <row><entry xml:id="function-type-string">scalar </entry><entry>string</entry> <entry><link xlink:href="http://www.lua.org/pil/2.4.html">"string"</link></entry> <entry>'A B C'</entry></row> - <row><entry xml:id="function-type-boolean">scalar </entry><entry>boolean</entry> <entry><link xlink:href="http://www.lua.org/pil/2.2.html">"boolean"</link></entry> <entry>true</entry></row> - <row><entry xml:id="function-type-nil">scalar </entry><entry>nil</entry> <entry><link xlink:href="http://www.lua.org/pil/2.1.html">"nil"</link></entry> <entry>nil</entry></row> - <row><entry xml:id="function-type-lua-table">compound</entry><entry>Lua table</entry> <entry><link xlink:href="http://www.lua.org/pil/2.5.html">"table"</link></entry> <entry>table: 0x410f8b10</entry></row> - <row><entry xml:id="function-type-tuple">compound </entry><entry>tuple</entry> <entry><link xlink:href="http://www.lua.org/pil/28.1.html">"Userdata"</link></entry><entry>12345: {'A B C'}</entry></row> - </tbody> - </tgroup> - </informaltable> - In Lua a "number" is double-precision floating-point; - however, for database storage Tarantool uses MsgPack rules, - and MsgPack allows for both integer and floating-point values. - So Tarantool will store a number as a float if the value contains a decimal point, and otherwise will store as an integer. - Tarantool can store signed numbers, but not in indexed fields -- when a field has a 'NUM' index, the values must be unsigned 64-bit integers. - Large numbers can be entered with exponential notation, for example 9e99. - Large integers greater than 100,000,000,000,000 (1e14) should be entered with the <ulink url="/doc/reference/other.html">tonumber64</ulink> function. - Storage is variable-length, so the smallest number requires only one byte but the largest number requires nine bytes. - </para> - <para> - A "string" is a variable-length sequence of bytes, usually represented with alphanumeric - characters inside single quotes. - </para> - <para> - A "boolean" is either <code>true</code> or <code>false</code>. - </para> - <para> - A "nil" type has only one possible value, also called "nil", but often displayed - as "null". Nils may be compared to values of any types with == (is-equal) or ~= - (is-not-equal), but other operations will not work. Nils may not be used in Lua tables; - the workaround is to use - <ulink url="/doc/reference/yaml.html"><code>yaml.NULL</code></ulink> - or <ulink url="/doc/reference/json.html"><code>json.NULL</code></ulink> - or <ulink url="/doc/reference/msgpack.html"><code>msgpack.NULL</code></ulink>. - </para> - <para> - A tuple is returned in YAML format like <code>- [120, 'a', 'b', 'c']</code>. - A few functions may return tables with 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, but not nil. - For more tuple examples see <code xlink:href="#box.tuple">box.tuple</code>. - </para> - - -<bridgehead renderas="sect2">Operations</bridgehead> - -<para> -The basic operations are: the four data-change operations -(insert, update, delete, replace), and the data-retrieval -operation (select). There are also minor operations like <quote>ping</quote> -which can only be used with the binary protocol. -Also, there are <olink -targetptr="box.index.iterator">index iterator</olink> operations, -which can only be used with Lua code. -(Index iterators are for traversing indexes one key at a time, -taking advantage of features that are specific -to an index type, for example evaluating Boolean expressions -when traversing BITSET indexes, or going in descending order -when traversing TREE indexes.) -</para> - -<para> -Five examples of basic operations: -<programlisting> --- Add a new tuple to tuple set tester. --- The first field, field[1], will be 999 (type is NUM). --- The second field, field[2], will be 'Taranto' (type is STR). -box.space.tester:insert{999, 'Taranto'} - --- Update the tuple, changing field field[2]. --- The clause "{999}", which has the value to look up in --- the index of the tuple's primary-key field, is mandatory --- because update() requests must always have a clause that --- specifies the primary key, which in this case is field[1]. --- The clause "{{'=', 2, 'Tarantino'}}" specifies that assignment --- will happen to field[2] with the new value. -box.space.tester:update({999}, {{'=', 2, 'Tarantino'}}) - --- Replace the tuple, adding a new field. --- This is also possible with the update() request but --- the update() request is usually more complicated. -box.space.tester:replace{999, 'Tarantella', 'Tarantula'} - --- Retrieve the tuple. --- The clause "{999}" is still mandatory, although it does not have to --- mention the primary key. */ -box.space.tester:select{999} - --- Delete the tuple. --- Once again the clause to identify the primary-key field is mandatory. -box.space.tester:delete{999} -</programlisting> -</para> - -<para> -How does Tarantool do a basic operation? Let's take this example: -<programlisting> -box.space.tester:update({3}, {{'=', 2, 'size'}, {'=', 3, 0}}) -</programlisting> -which, for those who know SQL, is equivalent to a statement like -UPDATE tester SET "field[2]" = 'size', "field[3]" = 0 WHERE "field[[1]" = 3 -</para> - -<para> -STEP #1: if this is happening on a remote client, then -the client parses the statement and changes it to a -binary-protocol instruction which has already been checked, -and which the server can understand without needing to parse -everything again. The client ships a packet to the server. -</para> -<para> -STEP #2: the server's <quote>transaction processor</quote> thread uses the -primary-key index on field[1] to find the location of the -tuple in memory. It determines that the tuple can be updated -(not much can go wrong when you're merely changing an unindexed -field value to something shorter). -</para> -<para> -STEP #3: the transaction processor thread sends a message to -the <emphasis>write-ahead logging<alt>There's a Wikipedia article about write-ahead logging: https://en.wikipedia.org/wiki/Write-ahead_logging</alt></emphasis> (WAL) thread. -</para> -<para> -At this point a <quote>yield</quote> takes place. To know -the significance of that -- and it's quite significant -- you -have to know a few facts and a few new words. -</para> -<para> -FACT #1: there is only one transaction processor thread. -Some people are used to the idea that there can be multiple -threads operating on the database, with (say) thread #1 -reading row #x while thread#2 writes row#y. With Tarantool -no such thing ever happens. Only the transaction processor -thread can access the database, and there is only one -transaction processor thread for each instance of the server. -</para> -<para> -FACT #2: the transaction processor thread can handle many -<emphasis>fibers<alt>There's a Wikipedia article about fibers: https://en.wikipedia.org/wiki/Fiber_%28computer_science%29</alt></emphasis>. -A fiber is a set of computer instructions that may contain <quote>yield</quote> signals. -The transaction processor thread will execute all computer instructions -until a yield, then switch to execute the instructions of a different fiber. -Thus (say) the thread reads row#x for the sake of fiber#1, -then writes row#y for the sake of fiber#2. -</para> -<para> -FACT #3: yields must happen, otherwise the transaction processor thread -would stick permanently on the same fiber. There are implicit yields: -every data-change operation or network-access causes an implicit yield, -and every statement that goes through the tarantool client causes an -implicit yield. And there are explicit yields: in a Lua function -one can and should add <quote>yield</quote> statements to prevent hogging. -This is called <emphasis>cooperative multitasking<alt>There's a Wikipedia -article with a section about cooperative multitasking: -https://en.wikipedia.org/wiki/Cooperative_multitasking#Cooperative_multitasking.2Ftime-sharing</alt></emphasis>. -</para> -<para> -Since all data-change operations end with an implicit yield and -an implicit commit, and since no data-change operation can change -more than one tuple, there is no need for any locking. -Consider, for example, a Lua function that does three Tarantool operations:<programlisting> -s:select{999} -- this does not yield and does not commit -s:update({...},{{...}}) -- this yields and commits -s:select{999} -- this does not yield and does not commit */</programlisting> -The combination <quote>SELECT plus UPDATE</quote> is an atomic transaction: -the function holds a consistent view of the database -until the UPDATE ends. For the combination <quote>UPDATE plus SELECT</quote> -the view is not consistent, because after the UPDATE the transaction processor -thread can switch to another fiber, and delete the tuple that -was just updated. -</para> -<para> -Since locks don't exist, and disk writes only involve the write-ahead log, -transactions are usually fast. Also the Tarantool server may not be -using up all the threads of a powerful multi-core processor, -so advanced users may be able to start a second Tarantool -server on the same processor without ill effects. -</para> -<para> - Additional examples of requests can be found in the <citetitle - xlink:href="https://github.com/tarantool/tarantool/tree/master/test/box" - xlink:title="Tarantool regression test suite">Tarantool - regression test suite</citetitle>. A complete grammar of - supported data-manipulation functions will come later in this chapter. -</para> -<para> - Since not all Tarantool operations can be expressed with the - data-manipulation functions, or with Lua, to gain - complete access to data manipulation functionality one must use - a <olink targetptr="connectors">Perl, PHP, Python or other - programming language connector</olink>. The client/server - protocol is open and documented: an annotated BNF can be found - in the source tree, file <filename - xlink:href="http://tarantool.org/doc/box-protocol.html" xlink:title="A complete BNF of Tarantool client/server protocol">doc/box-protocol.html</filename>. -</para> - -</section> -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/databases.xml b/doc/user/databases.xml deleted file mode 100644 index 70d7bfcdfd9c44d6ef70bd20fddf4ce6fae4303d..0000000000000000000000000000000000000000 --- a/doc/user/databases.xml +++ /dev/null @@ -1,3511 +0,0 @@ -<!DOCTYPE chapter [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:xi="http://www.w3.org/2001/XInclude" - xml:id="databases"> -<title>Databases</title> -<blockquote><para> - This chapter describes how Tarantool stores - values and what operations with data it supports. -</para></blockquote> - -<xi:include href="data-model.xml"/> -<xi:include href="persistence-architecture.xml"/> - -<section xml:id="data-manipulation"> - <title>Data manipulation</title> - - <para> - The basic "data-manipulation" requests are: - <code>insert</code>, <code>replace</code>, - <code>update</code>, <code>delete</code>, <code>select</code>. - They all are part of the <code>box</code> library. - They all may return data. - Usually both inputs and outputs may be Lua tables. - </para> - <para> - The Lua syntax for data-manipulation functions can vary. - Here are examples of the variations with <code>select</code> examples; - the same rules exist for the other data-manipulation functions. - Every one of the examples does the same thing: select a tuple set - from a space named tester where the primary-key field value equals 1. - </para> - <para> - First there are "naming variations": - <orderedlist xml:id="name-syntaxes" xreflabel="name-syntaxes"> - <listitem><para><code>box.space.tester:select{1}</code></para></listitem> - <listitem><para><code>box.space['tester']:select{1}</code></para></listitem> - <listitem><para><code>box.space[512]:select{1}</code></para></listitem> - <listitem><para><code>variable = 'tester'; box.space[variable]:select{1}</code></para></listitem> - </orderedlist> - ... There is an assumption that - the numeric id of 'tester' is 512, which happens to be the - case in our sandbox example only. Literal values such as - 'tester' may be replaced by variable names. - Examples and descriptions in this manual have the "box.space.space.tester:" form; - however, this is a matter of user preference and - all the variants exist in the wild. - </para> - <para> - Then there are "parameter variations": - <orderedlist xml:id="parameter-syntaxes" xreflabel="parameter-syntaxes"> - <listitem><para><code>box.space.tester:select{1}</code></para></listitem> - <listitem><para><code>box.space.tester:select({1})</code></para></listitem> - <listitem><para><code>box.space.tester:select(1)</code></para></listitem> - <listitem><para><code>box.space.tester:select({1},{iterator='EQ'})</code></para></listitem> - <listitem><para><code>variable = 1; box.space.tester:select{variable}</code></para></listitem> - <listitem><para><code>variable = {1}; box.space.tester:select(variable)</code></para></listitem> - </orderedlist> - ... The primary-key value is enclosed in braces, and if it was a - multi-part primary key then the value would be multi-part, - for example "...select{1,2,3}". The braces can be enclosed - inside parentheses -- "...select({...}) -- which is - optional unless it is necessary to pass something besides - the primary-key value, as in the fourth example. - Literal values such as 1 (a scalar value) or {1} - (a Lua table value) may be replaced by variable names, - as in examples [5] and [6]. - Although there are special cases where braces can be omitted, - they are preferable because they signal "Lua table". - Examples and descriptions in this manual have the "{1}" form; however, this - too is a matter of user preference and all the variants - exist in the wild. - </para> - - <para> - All the data-manipulation functions operate on tuple sets but, - since primary keys are unique, the number of tuples in the tuple set is always 1. - The only exception is <code>box.space...select</code>, which may accept either a - primary-key value or a secondary-key value. - </para> - -</section> - -<section xml:id="sp-box-library"> - <title>The <code>box</code> library</title> - - <para> - As well as executing Lua chunks or defining their own functions, - users can exploit the Tarantool server's storage functionality - with the <code>box</code> Lua library. - </para> - - <para> - <bridgehead renderas="sect4">Packages of the box library</bridgehead> - - The contents of the <code>box</code> library can be inspected at runtime with - <code>box</code>, with no arguments. - The packages inside the box library are: box.schema, box.tuple, box.space, box.index, - net.box, box.cfg, box.info, box.slab, box.stat. - Every package contains one or more Lua functions. A few packages contain members as well as functions. - The functions allow data definition (create alter drop), data manipulation (insert delete update select replace), - and introspection (inspecting contents of spaces, accessing server configuration). - </para> - - <para> - <table> - <title xml:id="complexity-factors">Complexity Factors that may affect data manipulation functions in the box library</title> - <tgroup cols="2" align="left" colsep="1" rowsep="1"> - <thead> - <row><entry>Factor</entry><entry>Explanation</entry></row> - </thead> - <tbody> - <row><entry>Index size</entry> <entry>The number of index keys is the same as the number - of tuples in the data set. For a TREE index, if - there are more keys then the lookup time will be - greater, although of course the effect is not linear. - For a HASH index, if there are more keys then there - is more RAM use, but the number of low-level steps - tends to remain constant.</entry></row> - <row><entry>Index type</entry> <entry>Typically a HASH index is faster than a TREE index - if the number of tuples in the tuple set is greater than one.</entry></row> - <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, can retrieve - multiple tuples. This factor is usually less - important than the others.</entry></row> - <row><entry>WAL settings</entry> <entry>The important setting for the write-ahead log is - <olink targetptr="wal_mode"/>. - If the setting causes no writing or delayed writing, - this factor is unimportant. If the settings causes - every data-change request to wait for writing to - finish on a slow device, this factor is more - important than all the others.</entry></row> - </tbody> - </tgroup> - </table> - In the discussion of each data-manipulation function there will be a note - about which Complexity Factors might affect the function's resource usage. - </para> - - <para> - <bridgehead renderas="sect4">The two storage engines: memtx and sophia</bridgehead> - A storage engine is a set of very-low-level routines which actually store and retrieve tuple values. - Tarantool offers a choice of two storage engines: memtx (the in-memory storage engine) - and sophia (the on-disk storage engine). To specify that the engine should be sophia, - add a clause: <code>engine = 'sophia'</code>. The manual concentrates on memtx because it is - the default and has been around longer. But sophia is a working key-value engine and will especially - appeal to users who like to see data go directly to disk, so that recovery time might be - shorter and database size might be larger. - For architectural explanations and benchmarks, see <link xlink:href="http://sphia.org">sphia.org</link>. - On the other hand, sophia lacks some functions and options that are available with memtx. - Where that is the case, the relevant description will contain the words - "only applicable for the memtx storage engine". - </para> - -</section> - -<section xml:id="sp-box-schema"> - <title>Package <code>box.schema</code></title> -<variablelist xml:id="box.schema" xreflabel="box.schema"> - <para> - The <code>box.schema</code> package has one data-definition - function: space.create(). - </para> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.space.create"> - box.schema.space.create(<replaceable>space-name</replaceable> [, {<replaceable>options</replaceable>} ]) - </emphasis> - </term> - <listitem> - <para> - Create a space. - </para> - <para> - Parameters: <code>space-name</code>, which should not be a number and should not contain special characters; - <code>options</code>. - </para> - <para> - <table> - <title>Options for box.schema.space.create</title> - <tgroup cols="4" align="left" colsep="1" rowsep="1"> - <tbody> - <row> - <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> - </row> - <row> - <entry>id</entry><entry>unique identifier</entry><entry>number</entry><entry>last space's id, +1</entry> - </row> - <row> - <entry>field_count</entry><entry>fixed field count</entry><entry>number</entry><entry>0 i.e. not fixed</entry> - </row> - <row> - <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> - <row> - <entry>user</entry><entry>user name</entry><entry>string</entry><entry>current user's name</entry> - </row> - </tbody> - </tgroup> - </table> - </para> - <para> - Returns: (type = tuple) the new space descriptor. - </para> - <para> - Possible errors: If a space with the same name already exists. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>s = box.schema.space.create('space55')</userinput> ---- -... -tarantool> <userinput>s = box.schema.space.create('space55', {id = 555, temporary = false})</userinput> ---- -- error: Space 'space55' already exists -... -tarantool> <userinput>s = box.schema.space.create('space55', {if_not_exists = true})</userinput> ---- -... -</programlisting> - After a space is created, usually the next step is to - <link linkend="box.create_index">create an index</link> for it, and - then it is available for insert, select, and all the other - <link linkend="box.space">box.space</link> functions. - </para> - </listitem> - </varlistentry> - - -</variablelist> - -</section> - -<section xml:id="sp-box-space"> - <title>Package <code>box.space</code></title> -<variablelist xml:id="box.space" xreflabel="box.space"> - <para> - The <code>box.space</code> package has the data-manipulation - functions <code>select</code>, <code>insert</code>, <code>replace</code>, <code>update</code>, - <code>delete</code>, <code>get</code>, <code>put</code>. - It also has members, such as id, and whether or not a space is - enabled. - Package source code is available in file <filename - xlink:href="https://github.com/tarantool/tarantool/blob/master/src/box/lua/box.lua">src/box/lua/box.lua</filename>. - </para> - - <para> - A list of all box.space functions follows, then comes a list of all <code>box.space</code> members. - </para> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.create_index"> - box.space.<replaceable>space-name</replaceable>:create_index(<replaceable>index-name</replaceable> [, {<replaceable>options</replaceable>} ]) - </emphasis> - </term> - <listitem> - <para> - Create an index. It is mandatory to create an index for a tuple set before trying to - insert tuples into it, or select tuples from it. The first created index, which will - be used as the primary-key index, must be unique. - </para> - <para> - Parameters: <code>index-name</code>, which should not be a number and should not contain special characters; - <code>options</code>. - </para> - <para> - <table> - <title>Options for box.space...create_index</title> - <tgroup cols="4" align="left" colsep="1" rowsep="1"> - <tbody> - <row> - <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'|'RTREE'</entry><entry>'TREE'</entry> - </row> - <row> - <entry>id</entry><entry>unique identifier</entry><entry>number</entry><entry>last index's id, +1</entry> - </row> - <row> - <entry>unique</entry><entry>index is unique</entry><entry>true|false</entry><entry>true</entry> - </row> - <row> - <entry>parts</entry><entry>field-numbers + types</entry><entry>{field_number, 'NUM'|STR'}</entry><entry>{1, 'NUM'}</entry> - </row> - <row> - <entry>if_not_exists</entry><entry>no error if duplicate name</entry><entry>true|false</entry><entry>false</entry> - </row> - </tbody> - </tgroup> - </table> - </para> - <para> - Returns: nil. - </para> - <para> - Possible errors: too many parts. - A type options other than TREE, or a unique option other than unique, or a parts option with more than one field component, - is only applicable for the memtx storage engine. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>s = box.space.space55</userinput> ---- -... -tarantool> <userinput>s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}})</userinput> ---- -... - -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.insert"> - box.space.<replaceable>space-name</replaceable>:insert{<replaceable>field-value [, field-value ...]</replaceable>} - </emphasis> - </term> - <listitem> - <para> - Insert a tuple into a space. - </para> - <para> - Parameters: <code>space-name</code>, <code> field-value(s)</code> = fields of the new tuple. - </para> - <para> - Returns: (type = tuple) the inserted tuple. - </para> - <para> - Possible errors: If a tuple with the same unique-key value already exists, returns ER_TUPLE_FOUND. - </para> - <para> - Example: <code><userinput>box.space.tester:insert{5000,'tuple number five thousand'}</userinput></code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.select" xreflabel="box.select"> - box.space.<replaceable>space-name</replaceable>:select{<replaceable>field-value [, field-value ...]</replaceable>} - </emphasis> - </term> - <listitem> - <para> - Search for a tuple or a set of tuples in the given space. - </para> - <para> - Parameters: (type = tuple, as a Lua table) <code>field-value(s)</code>— - = values to be matched against the index key, which may be multi-part. - </para> - <para> - Returns: (type = tuple set, as a Lua table) the tuples whose primary-key fields - are equal to the passed field-values. If the number of passed field-values is - less than the number of fields in the primary key, then only the passed field-values are - compared, so <code>select{1,2}</code> will match a tuple whose primary key is {1,2,3}. - </para> - <para> - Complexity Factors: Index size, Index type. - </para> - <para> - Possible Errors: No such space; wrong type. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>s = box.schema.space.create('tmp', {temporary=true})</userinput> ---- -... -tarantool> <userinput> s:create_index('primary',{parts = {1,'NUM', 2, 'STR'}})</userinput> ---- -... -tarantool> <userinput> s:insert{1,'A'}</userinput> ---- -- [1, 'A'] -... -tarantool> <userinput> s:insert{1,'B'}</userinput> ---- -- [1, 'B'] -... -tarantool> <userinput> s:insert{1,'C'}</userinput> ---- -- [1, 'C'] -... -tarantool> <userinput> s:insert{2,'D'}</userinput> ---- -- [2, 'D'] -... -tarantool> <userinput> s:select{1,'B'} -- must equal both primary-key fields</userinput> ---- -- - [1, 'B'] -... - -tarantool> <userinput> s:select{1} -- must equal only one primary-key field</userinput> ---- -- - [1, 'A'] - - [1, 'B'] - - [1, 'C'] -... -tarantool> <userinput> s:select{} -- must equal 0 fields, so returns all tuples</userinput> ---- -- - [1, 'A'] - - [1, 'B'] - - [1, 'C'] - - [2, 'D'] -...</programlisting> - For examples of complex <code>select</code>s, where one can specify which - index to search and what condition to use (for example "greater than" - instead of "equal to") and how many tuples to return, see the later section - <link linkend="box.index.iterator.select">box.space.space-name[.index.index-name]:select</link>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.get" xreflabel="box.get"> - box.space.<replaceable>space-name</replaceable>:get{<replaceable>field-value [, field-value ...]</replaceable>} - </emphasis> - </term> - <listitem> - <para> - Search for a tuple in the given space. - </para> - <para> - Parameters: (type = tuple, as a Lua table) <code>field-value(s)</code>— - = values to be matched against the index key, which may be multi-part. - </para> - <para> - Returns: (type = tuple) the selected tuple. - </para> - <para> - Complexity Factors: Index size, Index type. - </para> - <para> - Possible Errors: No such space; wrong type. - </para> - <para> - The <code>box.space...select</code> function returns a set of tuples as a Lua - table; the <code>box.space...get</code> function returns a single tuple. - And it is possible to get the first tuple in a tuple set by appending "[1]". - Therefore <code>box.space.tester:get{1}</code> has the same effect as - <code>box.space.tester:select{1}[1]</code>, and may serve as a convenient - shorthand. - </para> - <para> - Example: <code><userinput>box.space.tester:get{1}</userinput></code> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.drop"> - box.space.<replaceable>space-name</replaceable>:drop() - </emphasis> - </term> - <listitem> - <para> - Drop a space. - </para> - <para> - Parameters: none. - </para> - <para> - Returns: nil. - </para> - <para> - Complexity Factors: Index size, Index type, Number of indexes accessed, WAL settings. - </para> - <para> - 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> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.rename"> - box.space.<replaceable>space-name</replaceable>:rename(<replaceable>space-name</replaceable>) - </emphasis> - </term> - <listitem> - <para> - Rename a space. - </para> - <para> - Parameters: new name for space. - </para> - <para> - Returns: nil. - </para> - <para> - Possible errors: If space-name does not exist. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>box.space.space55:rename('space56')</userinput> ---- -... -tarantool> <userinput>box.space.space56:rename('space55')</userinput> ---- -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.space.alter"> - box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:alter({<replaceable>options</replaceable>}) - </emphasis> - </term> - <listitem> - <para> - Alter an index. - </para> - <para> - Parameters: <code>options</code> -- see the options list for create_index(). - </para> - <para> - Returns: nil. - </para> - <para> - Possible errors: The first index cannot be changed to {unique = false}. - The <code>alter</code> function is only applicable for the memtx storage engine. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>box.space.space55.index.primary:alter({type = 'HASH'})</userinput> ---- -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.space.drop"> - box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:drop() - </emphasis> - </term> - <listitem> - <para> - Drop an index. Dropping a primary-key index has a side effect: all tuples are deleted. - </para> - <para> - Parameters: none. - </para> - <para> - Returns: nil. - </para> - <para> - Possible errors: If index-name doesn't exist. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>box.space.space55.index.primary:drop()</userinput> ---- -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.space.rename"> - box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:rename(<replaceable>index-name</replaceable>) - </emphasis> - </term> - <listitem> - <para> - Rename an index. - </para> - <para> - Parameters: new name for index. - </para> - <para> - Returns: nil. - </para> - <para> - Possible errors: If index-name doesn't exist. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>box.space.space55.index.primary:rename('secondary')</userinput> ---- -... -</programlisting> - </para> - <para> - Complexity Factors: Index size, Index type, Number of tuples accessed. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.replace"> - box.space.<replaceable>space-name</replaceable>:replace{<replaceable>field-value [, field-value ...]</replaceable>} - </emphasis> - or - <emphasis role="lua" xml:id="box.put"> - box.space.<replaceable>space-name</replaceable>:put{<replaceable>field-value [, field-value ...]</replaceable>} - </emphasis> - </term> - <listitem> - <para> - Insert a tuple into a space. If a tuple with - the same primary key already exists, - <code>box.space...:replace()</code> replaces the existing - tuple with a new one. The syntax variants <code>box.space...:replace()</code> - and <code>box.space...:put()</code> have the same effect; the latter is sometimes - used to show that the effect is the converse of <code>box.space...:get()</code>. - </para> - <para> - Parameters: <code>space-name</code>, <code> field-value(s)</code> = fields of the new tuple. - </para> - <para> - Returns: (type = tuple) the inserted tuple. - </para> - <para> - Possible errors: If a different tuple with the same unique-key value already exists, returns ER_TUPLE_FOUND. - (This would only happen if there was a secondary index. By default secondary indexes are unique.) - </para> - <para> - Complexity Factors: Index size, Index type, Number of indexes accessed, WAL settings. - </para> - <para> - Example: <code><userinput>box.space.tester:replace{5000,'New value'}</userinput></code> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.update"> - box.space.<replaceable>space-name</replaceable>:update({<replaceable>key {, operator, field_number, value}...</replaceable>}) - </emphasis> - </term> - <listitem> - <para> - Update a tuple. - </para> - <para> - The <code>update</code> function supports operations on fields — - assignment, arithmetic, - cutting and pasting fragments of a field, - deleting or inserting a field. Multiple - operations can be combined in a single update request, and in this - case they are performed atomically and sequentially. Each operation requires - specification of a field number. When multiple operations - are present, the field number for each operation is assumed to - be relative to the most recent state of the tuple, that is, as if - all previous operations in a multi-operation update have - already been applied. In other words, it is always safe to - merge multiple <code>update</code> invocations into a single invocation, with no - change in semantics. - </para> - <para> - Parameters: <code>space-name</code>, - <code>key</code> = primary-key field values, must be passed as a Lua table if key is multi-part, - <code>{operator, field_number, value}</code> = a group of arguments - for each operation, indicating what the operation is, what field - the operation will apply to, and what value will be applied. - Possible operators are: - <quote>+</quote> or <quote>-</quote> for addition or subtraction (values must be numeric), - <quote>&</quote> or <quote>|</quote> or <quote>^</quote> for bitwise AND or OR or exclusive-OR - (values must be unsigned numeric), - <quote>:</quote> for string splice, - <quote>!</quote> for insertion, - <quote>#</quote> for deletion, - <quote>=</quote> for assignment. - For <quote>!</quote> and <quote>=</quote> operations the field number can be -1, meaning - the last field in the tuple. - Thus in the instruction <code>s:update(44, {{'+',1,55},{'=',3,'x'}})</code> - the primary-key value is 44, - the operators are '+' and '=' - meaning "add a value to a field - and then assign a value to a field", the first affected field - is field 1 and the value which will be added to it is 55, the second affected field - is field 3 and the value which will be assigned to it is 'x'. - </para> - <para> - Returns: (type = tuple) the updated tuple. - </para> - <para> - Possible errors: it is illegal to update a primary-key field. - </para> - <para> - Complexity Factors: Index size, Index type, number of indexes accessed, WAL settings. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -#Assume that the initial state of the database is ... -# tester has one tuple set and one primary key whose type is 'NUM'. -# There is one tuple, with field[1] = 999 and field[2] = 'A'. - -#In the following update ... -# The first argument is tester, that is, the affected space is tester -# The second argument is 999, that is, the affected tuple is identified by -# primary key value = 999 -# The third argument is '=', that is, there is one operation, assignment -# to a field -# The fourth argument is 2, that is, the affected field is field[2] -# The fifth argument is 'B', that is, field[2] contents change to 'B' -# Therefore, after the following update, field[1] = 999 and field[2] = 'B'. -box.space.tester:update(999, {{'=', 2, 'B'}}) - -#In the following update, the arguments are the same, except that ... -# the key is passed as a Lua table (inside braces). This is unnecessary -# when the primary key has only one field, but would be necessary if the -# primary key had more than one field. -# Therefore, after the following update, field[1] = 999 and field[2] = 'B' -# (no change). -box.space.tester:update({999}, {{'=', 2, 'B'}}) - -#In the following update, the arguments are the same, except that ... -# The fourth argument is 3, that is, the affected field is field[3]. -# It is okay that, until now, field[3] has not existed. It gets added. -# Therefore, after the following update, field[1] = 999, field[2] = 'B', -# field[3] = 1. -box.space.tester:update({999}, {{'=', 3, 1}}) - -#In the following update, the arguments are the same, except that ... -# The third argument is '+', that is, the operation is addition rather -# than assignment. -# Since field[3] previously contained 1, this means we're adding 1 to 1. -# Therefore, after the following update, field[1] = 999, field[2] = 'B', -# field[3] = 2. -box.space.tester:update({999}, {{'+', 3, 1}}) - -#In the following update ... -# The idea is to modify two fields at once. -# The formats are '|' and '=', that is, there are two operations, OR and -# assignment. -# The fourth and fifth arguments mean that field[3] gets ORed with 1. -# The seventh and eighth arguments mean that field[2] gets assigned 'C'. -# Therefore, after the following update, field[1] = 999, field[2] = 'C', -# field[3] = 3. -box.space.tester:update({999}, {{'|', 3, 1}, {'=', 2, 'C'}}) - -#In the following update ... -# The idea is to delete field[2], then subtract 3 from field[3], but ... -# after the delete, there is a renumbering -- so field[3] becomes field[2] -# before we subtract 3 from it, and that's why the seventh argument is 2 not 3. -# Therefore, after the following update, field[1] = 999, field[2] = 0. -box.space.tester:update({999}, {{'#', 2, 1}, {'-', 2, 3}}) - -#In the following update ... -# We're making a long string so that splice will work in the next example. -# Therefore, after the following update, field[1] = 999, field[2] = 'XYZ'. -box.space.tester:update({999}, {{'=', 2, 'XYZ'}}) - -#In the following update ... -# The third argument is ':', that is, this is the example of splice. -# The fourth argument is 2 because the change will occur in field[2]. -# The fifth argument is 2 because deletion will begin with the second byte. -# The sixth argument is 1 because the number of bytes to delete is 1. -# The seventh argument is '!!' because '!!' is to be added at this position. -# Therefore, after the following update, field[1] = 999, field[2] = 'X!!Z'. -box.space.tester:update({999}, {{':', 2, 2, 1, '!!'}}) - -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.delete"> - box.space.<replaceable>space-name</replaceable>:delete{<replaceable>field-value [, field-value ...]</replaceable>} - </emphasis> - </term> - <listitem> - <para> - Delete a tuple identified by a primary key. - </para> - <para> - Parameters: <code>space-name</code>, <code>field-value(s)</code> = values to match against keys in the primary index. - </para> - <para> - Returns: (type = tuple) the deleted tuple. - </para> - <para> - Complexity Factors: Index size, Index type - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>box.space.tester:delete(0)</userinput> ---- -- [0, 'My first tuple'] -... -tarantool> <userinput>box.space.tester:delete(0)</userinput> ---- -... -tarantool> <userinput>box.space.tester:delete('a')</userinput> -- error: 'Supplied key type of part 0 does not match index part type: - expected NUM' -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">box.space.<replaceable>space-name</replaceable>.id</emphasis></term> - <listitem> - <para> - (type = number) Ordinal space number. Spaces can be referenced by either name or number. - Thus, if space 'tester' has id = 800, then "box.space.tester:insert{0}" and "box.space[800]:insert{0}" - are equivalent requests. - </para> - </listitem> - </varlistentry> - <varlistentry> - - <term><emphasis role="lua">box.space.<replaceable>space-name</replaceable>.enabled</emphasis></term> - <listitem> - <para> - (type = boolean) Whether or not this space is enabled. The value is false if there is no index. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.space.field_count">box.space.<replaceable>space-name</replaceable>.field_count</emphasis> - </term> - <listitem> - <para> - (type = number) The required field count for all tuples in this space. - The field_count can be set initially with <code>box.schema.space.create<replaceable>... field_count = new-field-count-value ...</replaceable></code>. - The default value is 0, which means there is no required field count. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index[]</emphasis> - </term> - <listitem> - <para> - (type = table) A container for all defined indexes. An index is a Lua object - of type <code xlink:href="#box.index">box.index</code> with - methods to search tuples and iterate over them in predefined order. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester.id,box.space.tester.field_count,box.space.tester.index.primary.type</userinput> ---- -- 512 -- 0 -- TREE -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:len()</emphasis> - </term> - <listitem> - <para> - Returns: (type = number) number of tuples in the space. - The <code>len()</code> function is only applicable for the memtx storage engine. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester:len()</userinput> ---- - - 2 -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:truncate()</emphasis> - </term> - <listitem> - <para> - Deletes all tuples. - </para> - <para> - Complexity Factors: Index size, Index type, Number of tuples accessed. - </para> - <para> - Returns: nil. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester:truncate()</userinput> ---- -... -tarantool> <userinput>box.space.tester:len()</userinput> ---- - - 0 -... -</programlisting> - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:inc{<replaceable>field-value [, field-value ...]</replaceable>}</emphasis> - </term> - <listitem> - <para> - Increments a counter in a tuple whose primary key matches the field-value(s). - The field following the primary-key fields will be the counter. - If there is no tuple matching the field-value(s), a new one is inserted - with initial counter value set to 1. - </para> - <para>Parameters: <code>space-name</code>, <code>field-value(s)</code> = values - which must match the primary key. - </para> - <para> - Returns: (type = number) the new counter value. - </para> - <para> - Complexity Factors: Index size, Index type, WAL settings. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>s = box.schema.space.create('forty_second_space')</userinput> ---- -... -tarantool> <userinput>s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}})</userinput> ---- -... -tarantool> <userinput>box.space.forty_second_space:inc{1,'a'}</userinput> ---- -- 1 -... -tarantool> <userinput>box.space.forty_second_space:inc{1,'a'}</userinput> ---- -- 2 -...</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:dec{<replaceable>field-value [, field-value ...]</replaceable>}</emphasis> - </term> - <listitem> - <para> - Decrements a counter in a tuple whose primary key matches the field-value(s). - The field following the primary-key fields will be the counter. - If there is no tuple matching the field-value(s), a new one is not inserted. - If the counter value drops to zero, the tuple is deleted. - </para> - <para> - Parameters: <code>space-name</code>, <code>field-value(s)</code> = values - which must match the primary key. - </para> - <para> - Returns: (type = number) the new counter value. - </para> - <para> - Complexity Factors: Index size, Index type, WAL settings. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>s = box.schema.space.create('space19')</userinput> ---- -... -tarantool> <userinput>s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}})</userinput> ---- -... -tarantool> <userinput>box.space.space19:insert{1,'a',1000}</userinput> ---- -- [1, 'a', 1000] -... -tarantool> <userinput>box.space.space19:dec{1,'a'}</userinput> ---- -- 999 -... -tarantool> <userinput>box.space.space19:dec{1,'a'}</userinput> ---- -- 998 -... </programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:auto_increment{<replaceable>field-value [, field-value ...]</replaceable>}</emphasis> - </term> - <listitem> - <para> - Insert a new tuple using an auto-increment primary key. - The space specified by space-name must have a - NUM primary key index of type TREE. - The primary-key field will be incremented before the insert. - </para> - <para> - Parameters: <code>space-name</code>, <code>field-value(s)</code> = values for the tuple's fields, - other than the primary-key field. - </para> - <para> - Returns: (type = tuple) the inserted tuple. - </para> - <para> - Complexity Factors: Index size, Index type, Number of indexes accessed, WAL settings. - </para> - <para> - Possible errors: index has wrong type or primary-key indexed field is not a number. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester:auto_increment{'Fld#1', 'Fld#2'}</userinput> ---- -- [1, 'Fld#1', 'Fld#2'] -... -tarantool> <userinput>box.space.tester:auto_increment{'Fld#3'}</userinput> ---- -- [2, 'Fld#3'] -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:pairs()</emphasis> - </term> - <listitem> - <para> - A helper function to prepare for iterating over all tuples in a space. - </para> - <para> - Returns: (type = function) function which can be used in a for/end loop. - Within the loop, a value (type = tuple) is returned for each iteration. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting><prompt>tarantool></prompt> <userinput>s = box.schema.space.create('space33')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>s:create_index('X', {}) -- index 'X' has default parts {1,'NUM'}</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>s:insert{0,'Hello my '}; s:insert{1,'Lua world'}</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>tmp = ''; for k, v in s:pairs() do tmp = tmp .. v[2] end</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>tmp</userinput> ---- -- Hello my Lua world -...</programlisting> - </listitem> - </varlistentry> - - - <varlistentry> - <term> - <emphasis role="lua">box.space._schema</emphasis> - </term> - <listitem> - <para> - _schema is a system tuple set. Its single tuple contains these fields: - 'version', major-version-number, minor-version-number. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> - The following function will display all fields in all tuples of _schema. -<programlisting> -console = require('console'); console.delimiter('!') -function example() - local ta = {}, i, line - for k, v in box.space._schema:pairs() do - i = 1 - line = '' - while i <= #v do line = line .. v[i] .. ' ' i = i + 1 end - table.insert(ta, line) - end - return ta -end! -console.delimiter('')!</programlisting> - Here is what example() returns in a typical installation: -<programlisting> -<prompt>tarantool></prompt> <userinput>example()</userinput> ---- -- - 'cluster 1ec4e1f8-8f1b-4304-bb22-6c47ce0cf9c6 ' - - 'max_id 520 ' - - 'version 1 6 ' -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space._space</emphasis> - </term> - <listitem> - <para> - _space is a system tuple set. Its tuples contain these fields: - id, uid, space-name, engine, field_count, temporary. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> - The following function will display all simple fields in all tuples of _space. -<programlisting>console = require('console'); console.delimiter('!') -function example() - local ta = {}, i, line - for k, v in box.space._space:pairs() do - i = 1 - line = '' - while i <= #v do - if type(v[i]) ~= 'table' then - line = line .. v[i] .. ' ' - end - i = i + 1 - end - table.insert(ta, line) - end - return ta -end! -console.delimiter('')!</programlisting> - Here is what example() returns in a typical installation: -<programlisting> -<prompt>tarantool></prompt> <userinput>example()</userinput> ---- -- - '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 ' - - '320 1 _cluster memtx 0 ' - - '512 1 tester memtx 0 ' - - '513 1 origin sophia 0 ' - - '514 1 archive memtx 0 ' -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space._index</emphasis> - </term> - <listitem> - <para> - _index is a system tuple set. Its tuples contain these fields: - space-id index-id index-name index-type index-is-unique index-field-count - [tuple-field-no, tuple-field-type ...]. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> - The following function will display all fields in all tuples of _index. -<programlisting>console = require('console'); console.delimiter('!') -function example() - local ta = {}, i, line - for k, v in box.space._index:pairs() do - i = 1 - line = '' - while i <= #v do line = line .. v[i] .. ' ' i = i + 1 end - table.insert(ta, line) - end - return ta -end! -console.delimiter('')!</programlisting> - Here is what example() returns in a typical installation: -<programlisting> -<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 ' - - '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 1 owner tree 0 1 1 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 0 num ' - - '312 2 object tree 0 2 2 str 3 num ' - - '320 0 primary tree 1 1 0 num ' - - '320 1 uuid tree 1 1 1 str ' - - '512 0 primary tree 1 1 0 num ' - - '513 0 first tree 1 1 0 NUM ' - - '514 0 first tree 1 1 0 STR ' -...</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 <link linkend="authentication">authorization feature</link>. - </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> - - <varlistentry> - <term> - <emphasis role="lua">box.space._cluster</emphasis> - </term> - <listitem> - <para> - _cluster is a new system tuple set for support of the <olink targetptr="replication">replication feature</olink>. - </para> - </listitem> - </varlistentry> - - -</variablelist> - -<bridgehead renderas="sect4">Example showing use of the box.space functions</bridgehead> -<para> -This function will illustrate how to look at all the spaces, -and for each display: approximately -how many tuples it contains, and the first field of its first tuple. -The function uses Tarantool box.space functions len() and pairs(). -The iteration through the spaces is coded as a scan of the -_space system tuple set, which contains metadata. The third field in -_space contains the space name, so the key instruction "space_name = v[3]" -means "space_name = the space_name field in the tuple of _space -that we've just fetched with pairs()". The function returns a table. -</para> -<programlisting> -console = require('console'); console.delimiter('!') -function example() - local tuple_count, space_name, line - local ta = {} - for k, v in box.space._space:pairs() do - space_name = v[3] - if box.space[space_name].index[0] ~= nil then - tuple_count = box.space[space_name]:len() - else - tuple_count = 0 - end - line = space_name .. ' tuple_count =' .. tuple_count - if tuple_count > 0 then - for k1, v1 in box.space[space_name]:pairs() do - line = line .. '. first field in first tuple = ' .. v1[1] - break - end - end - table.insert(ta, line) - end - return ta -end! -console.delimiter('')! -</programlisting> -<para> -... And here is what happens when one invokes the function: -<programlisting> -<prompt>tarantool></prompt> <userinput>example()</userinput> ---- -- - _schema tuple_count =3. first field in first tuple = cluster - - _space tuple_count =15. first field in first tuple = 272 - - _index tuple_count =25. first field in first tuple = 272 - - _func tuple_count =1. first field in first tuple = 1 - - _user tuple_count =4. first field in first tuple = 0 - - _priv tuple_count =6. first field in first tuple = 1 - - _cluster tuple_count =1. first field in first tuple = 1 - - tester tuple_count =2. first field in first tuple = 1 - - origin tuple_count =0 - - archive tuple_count =13. first field in first tuple = test_0@tarantool.org - - space55 tuple_count =0 - - tmp tuple_count =0 - - forty_second_space tuple_count =1. first field in first tuple = 1 -... -</programlisting> -</para> - -</section> - -<section xml:id="sp-box-index"> - <title>Package <code >box.index</code></title> -<variablelist xml:id="box.index" xreflabel="box.index"> - <para> - The <code>box.index</code> package provides read-only access for index definitions and index keys. - Indexes are contained in <code - xlink:href="#box.space">box.space.<replaceable>space-name</replaceable>.index</code> array - within each space object. They provide an API for - ordered iteration over tuples. This API is a direct - binding to corresponding methods of index objects of type <code>box.index</code> in the - storage engine. - </para> - <varlistentry> - <term><emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>.unique</emphasis></term> - <listitem> - <para> - (type = boolean) true if the index is unique. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>.type</emphasis> - </term> - <listitem> - <para> - (type = string) index type, 'TREE' or 'HASH' or 'BITSET' or 'RTREE'. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>.parts</emphasis> - </term> - <listitem> - <para> - An array describing index key fields. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term></term> - <listitem><bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester.index.primary</userinput> ---- - unique: true - parts: - 0: - type: NUM - fieldno: 1 - id: 0 - space_id: 513 - name: primary - type: TREE -...</programlisting></listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="boxindexiterator" xreflabel="box.index.iterator(type, ...)"> - box.space.<replaceable>space-name</replaceable>.index[.<replaceable>index-name</replaceable>]:pairs(<replaceable>bitset-value | field-value..., iterator-type</replaceable>)</emphasis> - </term> - <listitem> - <para> - This method provides iteration support within an - index. Parameter <code>type</code> is used to - identify the semantics of iteration. Different - index types support different iterators. The - remaining arguments of the function are varying - and depend on the iteration type. For example, - a TREE index maintains a strict order of keys and - can return all tuples in ascending or descending - order, starting from the specified key. Other - index types, however, do not support ordering. - </para> - <para xml:id="iterator-consistency"> - To understand consistency of tuples - returned by an iterator, it's essential to know - the principles of the Tarantool transaction processing - subsystem. - An iterator in Tarantool does not own a consistent - read view. Instead, each procedure is granted exclusive - access to all tuples and spaces until it - encounters a "context switch": by causing a write to - disk, network, or by an explicit call to <emphasis - role="lua" xlink:href="/doc/reference/fiber.html#fiber.yield">fiber.yield()</emphasis>. - When the execution flow returns to the yielded - procedure, the data set could have changed significantly. - Iteration, resumed after a yield point, does not - preserve the read view, but continues with the new - content of the database. - </para> - <para> - Parameters: - <code>type</code> — iteration strategy as defined in tables below. - </para> - <para> - Returns: this method returns an iterator closure, i.e. - a <code>function</code> which can be used to - get the next value on each invocation. - </para> - <para> - Complexity Factors: Index size, Index type, Number of tuples accessed. - </para> - <para> - Possible Errors: - Selected iteration type is not supported in - the subject index type, or supplied parameters - do not match iteration type. - </para> - - <xi:include href="iterator-types.xml"/> - - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -<prompt>tarantool></prompt> <userinput> s = box.schema.space.create('space17')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> s:create_index('primary', {parts = {1, 'STR', 2, 'STR'}})</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> s:insert{'C', 'C'}</userinput> ---- -- ['C', 'C'] -... -<prompt>tarantool></prompt> <userinput> s:insert{'B', 'A'}</userinput> ---- -- ['B', 'A'] -... -<prompt>tarantool></prompt> <userinput> s:insert{'C', '!'}</userinput> ---- -- ['C', '!'] -... -<prompt>tarantool></prompt> <userinput> s:insert{'A', 'C'}</userinput> ---- -- ['A', 'C'] -... -<prompt>tarantool></prompt> <userinput> console = require('console'); console.delimiter('!')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> function example() - > for _, tuple in - > s.index.primary:pairs(nil, {iterator = box.index.ALL}) do - > print(tuple) - > end - > end!</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> console.delimiter('')!</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> example()</userinput> -['A', 'C'] -['B', 'A'] -['C', '!'] -['C', 'C'] ---- -... -<prompt>tarantool></prompt> <userinput>s:drop()</userinput> ---- -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="box.index.iterator.select" xreflabel="box.index.select(type, ...)"> - box.space.<replaceable>space-name</replaceable>[.index.<replaceable>index-name</replaceable>]:select({<replaceable>[field-value [, field-value ...]]</replaceable>}, {<replaceable>[option [, option ...]]</replaceable>})</emphasis> - </term> - <listitem> - <para> - This is is an alternative to <olink targetptr="box.select">box.space...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) and the offset (that is, which tuple to start with in the list). - </para> - <para> - Parameters: <code>field-value(s)</code> = values to be matched against the index key. - <code>option(s)</code> = any or all of <code>iterator=<replaceable>iterator-type</replaceable></code>, - <code>limit=<replaceable>maximum-number-of-tuples</replaceable></code>, - <code>offset=<replaceable>start-tuple-number</replaceable></code>. - </para> - <para> - Returns: (type = tuple set, as a Lua table) the tuple or tuples that match the field values. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -# Create a space named tester. -# 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[2] equal to 'X', 'Y', and 'Z'. -# Select all tuples where the secondary index keys are greater than 'X'. -box.schema.space.create('tester') -box.space.tester:create_index('primary', {parts = {1, 'NUM' }}) -box.space.tester:create_index('secondary', {type = 'tree', unique = false, parts = {2, 'STR'}}) -box.space.tester:insert{1,'X','Row with field[2]=X'} -box.space.tester:insert{2,'Y','Row with field[2]=Y'} -box.space.tester:insert{3,'Z','Row with field[2]=Z'} -box.space.tester.index.secondary:select({'X'}, {iterator = 'GT', limit = 1000}) -</programlisting> -The result will be a table of tuples and will look like this: -<programlisting> ---- -- - [2, 'Y', 'Row with field[2]=Y'] - - [3, 'Z', 'Row with field[2]=Z'] -... -</programlisting> - </para> - <para> - Note: <code>[.index.<replaceable>index-name</replaceable>]</code> is optional. If it is - omitted, then the assumed index is the first (primary-key) index. Therefore, for - the example above, <code>box.space.tester:select({1}, {iterator = 'GT'})</code> - would have returned the same two rows, via the 'primary' index. - </para> - <para> - Note: <code>iterator = <replaceable>iterator type</replaceable></code> is optional. - If it is omitted, then <code>iterator = 'EQ'</code> is assumed. - </para> - <para> - Note: <code><replaceable>field-value [, field-value ...]</replaceable></code> is optional. - If it is omitted, then every key in the index is considered to be a match, - regardless of iterator type. - Therefore, for the example above, <code>box.space.tester:select{}</code> - will select every tuple in the tester space via the first (primary-key) index. - </para> - <para> - Note: <code>box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:select(...)[1]</code>. - can be replaced by <code>box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:get(...)</code>. - That is, <code>get</code> can be used as a convenient shorthand to get the first - tuple in the tuple set that would be returned by <code>select</code>. - However, if there is more than one tuple in the tuple set, then <code>get</code> returns an error. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:min([<replaceable>key-value</replaceable>])</emphasis> - </term> - <listitem> - <para> - Find the minimum value in the specified index. - </para> - <para> - Returns: (type = tuple) the tuple for the first key in the index. - If optional <code>key-value</code> is supplied, returns the first key which is greater than or equal to key-value. - </para> - <para> - Complexity Factors: Index size, Index type. - </para> - <para> - Possible errors: index is not of type 'TREE'. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester.index.primary:min()</userinput> ---- -- ['Alpha!', 55, 'This is the first tuple!'] -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:max([<replaceable>key-value</replaceable>])</emphasis> - </term> - <listitem> - <para> - Find the maximum value in the specified index. - </para> - <para> - Returns: (type = tuple) the tuple for the last key in the index. - If optional <code>key-value</code> is supplied, returns the last key which is less than or equal to key-value. - </para> - <para> - Complexity Factors: Index size, Index type. - </para> - <para> - Possible errors: index is not of type 'TREE'. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester.index.primary:max()</userinput> ---- -- ['Gamma!', 55, 'This is the third tuple!'] -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:random(<replaceable>random-value</replaceable>)</emphasis> - </term> - <listitem> - <para> - Find a random value in the specified index. - This method is useful when it's important to get insight - into data distribution in an index without having to - iterate over the entire data set. - </para> - <para> - Parameters: <code>random-value</code> = an arbitrary non-negative integer. - </para> - <para> - Returns: (type = tuple) the tuple for the random key in the index. - </para> - <para> - Complexity Factors: Index size, Index type. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester.index.secondary:random(1)</userinput> ---- -- ['Beta!', 66, 'This is the second tuple!'] -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>:count(<replaceable>key-value</replaceable>, <replaceable>options</replaceable>)</emphasis> - </term> - <listitem> - <para> - Iterate over an index, counting the number of tuples which equal the - provided search criteria. - </para> - <para> - Parameters: <code>key-value</code> = the value which must match the key(s) - in the specified index. The type may be a list of field-values, or a tuple containing - only the field-values. - </para> - <para> - Returns: (type = number) the number of matching index keys. - The <code>index</code> function is only applicable for the memtx storage engine. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>box.space.tester.index.primary:count(999)</userinput> ---- -- 0 -... -</programlisting> -<programlisting>tarantool> <userinput>box.space.tester.index.primary:count('Alpha!', { iterator = 'LE' })</userinput> ---- - - 1 -... -</programlisting> - </para> - </listitem> - </varlistentry> - -</variablelist> - -<bridgehead renderas="sect4">Example showing use of the box functions</bridgehead> -<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 tester with a numeric primary key. -The example function will: (1) select a 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[1] = 1000, field[2] = a uuid, field[3] = number of seconds since 1970-01-01; -(4) Get field[3] from what was replaced; -(5) Format the value from field[3] as yyyy-mm-dd hh:mm:ss.ffff; -(6) Return the formatted value. -The function uses Tarantool box functions <code>box.space...select</code>, <code>box.space...replace</code>, <code>fiber.time</code>, <code>uuid.str()</code>. -The function uses Lua functions -<link xlink:href="http://www.lua.org/pil/22.1.html">os.date()</link> -and <link xlink:href="http://www.lua.org/pil/20.html">string.sub()</link>. -</para> -<programlisting> -console = require('console'); console.delimiter('!') -function example() - local a, b, c, table_of_selected_tuples, replaced_tuple, time_field - local formatted_time_field - local fiber = require('fiber') - table_of_selected_tuples = box.space.tester: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.error({code=1, reason='This tuple already has 3 fields'}) - end - end - end - replaced_tuple = box.space.tester:replace - {1000, require('uuid').str(), tostring(fiber.time())} - time_field = tonumber(replaced_tuple[3]) - formatted_time_field = os.date("%Y-%m-%d %H:%M:%S", time_field) - c = time_field % 1 - d = string.sub(c, 3, 6) - formatted_time_field = formatted_time_field .. '.' .. d - return formatted_time_field -end! -console.delimiter('')! -</programlisting> -<para> -... And here is what happens when one invokes the function: -<programlisting> -<prompt>tarantool></prompt> <userinput>box.space.tester:delete(1000)</userinput> ---- -- 1000: {'264ee2da03634f24972be76c43808254', '1391037015.6809'} -... -<prompt>tarantool></prompt> <userinput>example(1000)</userinput> ---- -- 2014-01-29 16:11:51.1582 -... -<prompt>tarantool></prompt> <userinput>example(1000)</userinput> ---- -- error: 'This tuple already has 3 fields' -... -</programlisting> -</para> - -</section> - -<section xml:id="RTREE"> - <title>Package <code >box.index</code> with index type = RTREE for spatial searches</title> - <para> - The <code>box.index</code> package may be used for spatial searches - if the index type is RTREE. There are operations for searching - <emphasis>rectangles</emphasis>. Rectangles are described according - to their X-axis (horizontal axis) and Y-axis (vertical axis) - coordinates in a grid of arbitrary size. Here is a picture of four - rectangles on a grid with 11 horizontal points and 11 vertical points: -<programlisting> - X AXIS - 1 2 3 4 5 6 7 8 9 10 11 - 1 - 2 *-------+ <-Rectangle#1 -Y AXIS 3 | | - 4 +-------* - 5 *-----------------------+ <-Rectangle#2 - 6 | | - 7 | *---+ | <-Rectangle#3 - 8 | | | | - 9 | +---* | - 10 +-----------------------* - 11 * <-Rectangle#4 -</programlisting> - The rectangles are defined according to this scheme: - {X-axis coordinate of top left, - Y-axis coordinate of top left, - X-axis coordinate of bottom right, - Y-axis coordinate of bottom right} -- or more succinctly: - {x1,y1,x2,y2}. So in the picture ... - Rectangle#1 starts at position 1 on the X axis and position - 2 on the Y axis, and ends at position 3 on the X axis and - position 4 on the Y axis, so its coordinates are - {1,2,3,4}. Rectangle#2's coordinates are {3,5,9,10}. - Rectangle#3's coordinates are {4,7,5,9}. And finally - Rectangle#4's coordinates are {10,11,10,11}. - Rectangle#4 is actually a "point" since it has zero - width and zero height, so it could have been described - with only two digits: {10,11}. - </para> - <para> - Some relationships between the rectangles are: - "Rectangle#1's nearest neighbor is Rectangle#2", and - "Rectangle#3 is entirely inside Rectangle#2". - </para> - <para> - Now let us create a space and add an RTREE index. -<programlisting> -<userinput>s = box.schema.create_space('rectangles')</userinput> -<userinput>i = s:create_index('primary',{type='HASH',parts={1,'NUM'}})</userinput> -<userinput>r = s:create_index('spatial',{type='RTREE',unique=false,parts={2,'ARRAY'}})</userinput> -</programlisting> - Field#1 doesn't matter, we just make it because we need a primary-key index. - (RTREE indexes cannot be unique and therefore cannot be primary-key indexes.) - The second field must be an "array", which means its values must represent - {x,y} points or {x1,y1,x2,y2} rectangles. - Now let us populate the table by inserting two tuples, - containing the coordinates of Rectangle#2 and Rectangle#4. -<programlisting> -<userinput>s:insert{1, {3,5,9,10}}</userinput> -<userinput>s:insert{2, {10,11}}</userinput> -</programlisting> - and now, following the description of <link linkend="rtree-iterator">RTREE iterator types</link>, - we can search the rectangles with these requests: -<programlisting> -<userinput>r:select({10,11,10,11},{iterator='EQ'}) -- Request#1 (returns 1 tuple)</userinput> -<userinput>r:select({4,7,5,9},{iterator='GT'}) -- Request#2 (returns 1 tuple)</userinput> -<userinput>r:select({1,2,3,4},{iterator='NEIGHBOR'}) -- Request#3 (returns 2 tuples)</userinput> -</programlisting> - Request#1 returns 1 tuple because the point {10,11} is the same as the - rectangle {10,11,10,11} ("Rectangle#4" in the picture). - Request#2 returns 1 tuple because the rectangle {4,7,5,9}, which was - "Rectangle#3" in the picture, is entirely within{3,5,9,10} which was Rectangle#2. - Request#3 returns 2 tuples, because the NEIGHBOR iterator always returns all - tuples, and the first returned tuple will be {3,5,9,10} ("Rectangle#2" in - the picture) because it is the closest neighbor of {1,2,3,4} ("Rectangle#1" - in the picture). - </para> - <para> - More examples of spatial searching are online in the file - <link xlink:href="https://github.com/tarantool/tarantool/wiki/R-tree-index-quick-start-and-usage">"R tree index quick start and usage"</link>. - </para> -</section> - -<section xml:id="sp-error"> - <title>Package <code>box.error</code></title> - <para> - The <code>box.error</code> function is for raising an error. - The difference between this function - and Lua's built-in <code>error()</code> function - is that when the error reaches the client, its error code - is preserved. In contrast, a Lua error would always be - presented to the client as <constant>ER_PROC_LUA</constant>. - </para> -<variablelist xml:id="error" xreflabel="error"> - - <varlistentry> - <term> - <emphasis role="lua">box.error({[code=<replaceable>errcode-number</replaceable>,] reason=<replaceable>errtext-string</replaceable>})</emphasis> - </term> - <listitem> - <para> - When called with a Lua-table argument, the errorcode-number and errtext-string have any user-desired values. - The result will be those values. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.error()</emphasis> - </term> - <listitem> - <para> - When called without arguments, <code>box.error()</code> re-throws whatever the last error was. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.error(<replaceable>errcode-number, errtext-string [, errtext-string ...]</replaceable>)</emphasis> - </term> - <listitem> - <para> - Emulate a request error, with text based on one of the pre-defined Tarantool errors defined in - the file <link xlink:href="https://github.com/tarantool/tarantool/blob/master/src/errcode.h"><filename>errcode.h</filename></link> - in the source tree. Lua constants which correspond to those Tarantool errors - are defined as members of <code>box.error</code>, for example <code>box.error.NO_SUCH_USER</code> == 45. - </para> - <para> - Parameters: <code>errcode-number</code> = number of a pre-defined error, - <code>errtext-string</code> = part of the message which will accompany the error. - For example the NO_SUCH_USER message is "User '%s' is not found" -- it includes one - "%s" component which will be replaced with <code>errtext-string</code>. Thus a call to - <code>box.error(box.error.NO_SUCH_USER, 'joe')</code> or - <code>box.error(45, 'joe')</code> will result in an error with the accompanying - message "User 'joe' is not found". - </para> - <para> - Possible errors: whatever is specified in errcode-number. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting><prompt>tarantool></prompt> <userinput>box.error({code=555, reason='Arbitrary message'})</userinput> ---- -- error: Arbitrary message -... - -<prompt>tarantool></prompt> <userinput>box.error()</userinput> ---- -- error: Arbitrary message -... - -<prompt>tarantool></prompt> <userinput>box.error(box.error.FUNCTION_ACCESS_DENIED, 'A', 'B', 'C')</userinput> ---- -- error: A access denied for user 'B' to function 'C' -...</programlisting> - </listitem> - </varlistentry> - -</variablelist> -</section> - -<section xml:id="sp-box-tuple"> - <title>Package <code>box.tuple</code></title> -<variablelist xml:id="box.tuple" xreflabel="box.tuple"> - <para>The <code>box.tuple</code> package provides read-only access for the <code>box.tuple</code> userdata - type. It allows, for a single tuple: selective retrieval of the - field contents, retrieval of information about size, - iteration over all the fields, and conversion to a Lua table. - </para> - <varlistentry> - <term> - <emphasis role="lua">box.tuple.new(<replaceable>scalar-value | Lua-table-value</replaceable>)</emphasis> - </term> - <listitem> - <para> - Construct a new tuple from either a scalar or a Lua table. - Alternatively, one can get new tuples from tarantool's - SQL-like statements: SELECT, INSERT, UPDATE, REPLACE, - which can be regarded as statements that do new() - implicitly. - </para> - <para> - Parameters: <code>scalar-value | Lua-table-value</code> = the value that will become the tuple contents. - </para> - <para> - Returns: (type = tuple) a new tuple. - </para> - <para> - In the following example, x 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>tarantool> <userinput>x = box.space.tester:insert{33,tonumber('1'),tonumber64('2')}:totable()</userinput> ---- -... -tarantool> <userinput>t = box.tuple.new({'abc', 'def', 'ghi', 'abc'})</userinput> ---- -... -tarantool> <userinput>t</userinput> ---- -- ['abc', 'def', 'ghi', 'abc'] -...</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua"># <replaceable>tuple-value</replaceable></emphasis> - </term> - <listitem> - <para> - The # operator in Lua means "return count of components". - So, if t is a tuple instance, <code>#t</code> - will return the number of - fields. - </para> - <para> - Returns: (type = number) number of fields. - </para> - <para> - In the following example, a tuple named t is created - and then the number of fields in t is returned. - </para> - <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput> ---- -... -tarantool> <userinput>#t</userinput> ---- -- 4 -...</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua"> <replaceable>tuple-value</replaceable>:bsize()</emphasis> - </term> - <listitem> - <para> - If t is a tuple instance, <code>t:bsize()</code> - will return the number of bytes in the tuple. - It is useful to check this number when making changes to data, - because there is a fixed maximum: one megabyte. - Every field has one or more "length" bytes preceding the - actual contents, so bsize() returns a value which is - slightly greater than the sum of the lengths of the contents. - </para> - <para> - Returns: (type = number) number of bytes. - </para> - <para> - In the following example, a tuple named t is created - which has three fields, and for each field it takes one byte - to store the length and three bytes to store the contents, - and a bit for overhead, so bsize() returns 3*(1+3)+1. - </para> - <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>tarantool> <userinput>t = box.tuple.new({'aaa','bbb','ccc'})</userinput> ---- -... -tarantool> <userinput>t:bsize()</userinput> ---- - - 13 -...</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua"><replaceable>tuple-value</replaceable> [ <replaceable>field-number</replaceable> ]</emphasis> - </term> - <listitem> - <para> - If t is a tuple instance, <code>t[<replaceable>field-number</replaceable>]</code> - will return the field numbered <code>field-number</code> in the tuple. - The first field is t[1]. - </para> - <para> - Returns: (type = scalar) field value. - </para> - <para> - In the following example, a tuple named t is created - and then the second field in t is returned. - </para> - <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4'})</userinput> ---- -... -tarantool> <userinput>t[2]</userinput> ---- - - Fld#2 -...</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua"><replaceable>tuple-value</replaceable>:find(<replaceable>[field-number,] field-value</replaceable>) or <replaceable>tuple-value</replaceable>:findall(<replaceable>[field-number,] field-value</replaceable>)</emphasis> - </term> - <listitem> - <para> - If t is a tuple instance, <code>t:find(<replaceable>field-value</replaceable>)</code> - will return the number of the first field in t that matches the field value), and - <code>t:findall(<replaceable>field-value [, field-value ...]</replaceable>)</code> - will return numbers of all fields in t that match the field value. Optionally - one can put a numeric argument field-number before the search-value to indicate - <quote>start searching at field number <code>field-number</code>.</quote> - </para> - <para> - Returns: (type = number) the number of the field in the tuple. - </para> - <para> - In the following example, a tuple named t is created - and then: the number of the first field in t which matches 'a' is returned, - then the numbers of all the fields in t which match 'a' are returned, - then the numbers of all the fields in t which match 'a' and are at or after the second field - are returned. - </para> - <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>tarantool> <userinput>t = box.tuple.new({'a','b','c','a'})</userinput> ---- -... -tarantool> <userinput>t:find('a')</userinput> ---- -- 1 -... -tarantool> <userinput>t:findall('a')</userinput> ---- -- 1 -- 4 -... -tarantool> <userinput>t:findall(2, 'a')</userinput> ---- - - 4 -...</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua"><replaceable>tuple-value</replaceable>:transform(<replaceable>start-field-number, fields-to-remove [, field-value ...]</replaceable>)</emphasis> - </term> - <listitem> - <para> - If t is a tuple instance, <code>t:transform(<replaceable>start-field-number</replaceable>,<replaceable>fields-to-remove</replaceable>)</code> - will return a tuple where, starting from field start-field-number, a number of fields (fields-to-remove) are removed. - Optionally one can add more arguments after fields-to-remove to indicate new values that will replace - what was removed. - </para> - <para> - Parameters: <code>start-field-number</code> = base 1, may be negative, <code>fields-to-remove</code>, <code>field-values(s)</code>. - </para> - <para> - Returns: (type = tuple) a new tuple. - </para> - <para> - In the following example, a tuple named t is created - and then, starting from the second field, two fields are removed - but one new one is added, then the result is returned. - </para> - <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> ---- -... -tarantool> <userinput>t:transform(2,2,'x')</userinput> ---- -- ['Fld#1', 'x', 'Fld#4', 'Fld#5'] -...</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua"><replaceable>tuple-value</replaceable>:unpack()</emphasis> - </term> - <listitem> - <para> - If t is a tuple instance, <code>t:unpack(<replaceable>n</replaceable>)</code> - will return all fields. - </para> - <para> - Returns: (type = scalar) field(s) from the tuple. - </para> - <para> - In the following example, a tuple named t is created - and then all its fields are selected, - then the result is returned. - </para> - <bridgehead renderas="sect4">Example</bridgehead> - <programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> ---- -... -tarantool> <userinput>t:unpack()</userinput> ---- - - Fld#1 - - Fld#2 - - Fld#3 - - Fld#4 - - Fld#5 -...</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua"><replaceable>tuple-value</replaceable>:pairs()</emphasis> - </term> - <listitem> - <para> - In Lua, lua-table-value:pairs() is a method which returns: function, lua-table-value, nil. - Tarantool has extended this so that tuple-value:pairs() returns: function, tuple-value, nil. - It is useful for Lua iterators, because Lua iterators traverse - a value's components until an end marker is reached. - </para> - <para> - Returns: (type = function) function, (type = tuple) tuple-value, (type = nil) nil. - </para> - <para> - In the following example, a tuple named t is created - and then all its fields are selected using a Lua for-end loop. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> ---- -... -tarantool> <userinput>tmp = ''; for k, v in t:pairs() do tmp = tmp .. v end</userinput> ---- -... -tarantool> <userinput>tmp</userinput> ---- -- Fld#1Fld#2Fld#3Fld#4Fld#5 -...</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua"><replaceable>tuple-value</replaceable>:update(<replaceable>{{format, field_number, value}...}</replaceable>)</emphasis> - </term> - <listitem> - <para> - Update a tuple. - </para> - <para> - This function updates a tuple which is not in a space. - Compare the function - <code>box.space.<replaceable>space-name</replaceable>:update{<replaceable>key, format, {field_number, value}...</replaceable>)</code>, - which updates a tuple in a space. - </para> - <para> - Parameters: briefly: - <code>format</code> indicates the type of update operation such as '=' for 'assign new value', - <code>field_number</code> indicates the field number to change such as 2 for field number 2, - <code>value</code> indicates the string which operates on the field such as 'B' for a new assignable value = 'B'. - For details: see the description for <code>format</code>, <code>field_number</code>, and <code>value</code> - in the section <olink targetptr="box.update"><code>box.space.<replaceable>space-name</replaceable>:update{<replaceable>key, format, {field_number, value}...</replaceable>)</code></olink>. - </para> - <para> - Returns: (type = tuple) the new tuple. - </para> - <para> - In the following example, a tuple named t is created - and then its second field is updated to equal 'B'. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>t = box.tuple.new({'Fld#1','Fld#2','Fld#3','Fld#4','Fld#5'})</userinput> ---- -... -tarantool> <userinput>t:update({{'=',2,'B'}})</userinput> ---- -- ['Fld#1', 'B', 'Fld#3', 'Fld#4', 'Fld#5'] -...</programlisting> - </listitem> - </varlistentry> - -</variablelist> - -<bridgehead renderas="sect4">Example showing use of the box.tuple functions</bridgehead> -<para> -This function will illustrate how to convert tuples to/from -Lua tables and lists of scalars: -<programlisting> - scalars to tuple: tuple = box.tuple.new({scalar1, scalar2, ... scalar_n}) - tuple to Lua table: lua_table = {tuple:unpack()} - tuple to scalars: scalar1, scalar2, ... scalar_n = tuple:unpack() - Lua table to tuple: tuple = box.tuple.new(lua_table) -</programlisting> -Then it will find the field that contains 'b', -remove that field from the tuple, -and display how many bytes remain in the tuple. -The function uses Tarantool box.tuple functions new(), unpack(), find(), transform(), bsize(). -</para> -<programlisting> -console = require('console'); console.delimiter('!') -function example() - local tuple1, tuple2, lua_table_1, scalar1, scalar2, scalar3, field_number - tuple1 = box.tuple.new({'a', 'b', 'c'}) - luatable1 = {tuple1:unpack()} - scalar1, scalar2, scalar3 = tuple1:unpack() - tuple2 = box.tuple.new(luatable1) - field_number = tuple2:find('b') - tuple2 = tuple2:transform(field_number, 1) - return 'tuple2 = ' , tuple2 , ' # of bytes = ' , tuple2:bsize() -end! -console.delimiter('')! -</programlisting> -<para> -... And here is what happens when one invokes the function: -<programlisting> -<prompt>tarantool></prompt> <userinput>example()</userinput> ---- -- 'tuple2 = ' -- ['a', 'c'] -- ' # of bytes = ' -- 5 -... -</programlisting> -</para> - -</section> - -<!-- end of lib --> - - -<!-- end of lib --> - -<!-- end of lib --> - -<section xml:id="sp-box-cfg"> - <title>Packages <code>box.cfg</code>, - <code>box.info</code>, <code>box.slab</code> and - <code>box.stat</code>: server introspection</title> - -<variablelist> - <title>Package <code xml:id="box.cfg">box.cfg</code></title> - <para> - The box.cfg package is for administrators to specify all the server configuration parameters; - the full description of the parameters is in section <olink targetptr="configuration-file">Configuration</olink>. - Use <code>box.cfg</code> without braces to get read-only access to those parameters. - </para> - <varlistentry> - <term><emphasis role="lua">box.cfg</emphasis></term> - <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting> -tarantool> <userinput>box.cfg</userinput> ---- -- too_long_threshold: 0.5 - slab_alloc_factor: 2 - slab_alloc_minimal: 64 - background: false - slab_alloc_arena: 1 - log_level: 5 - ... -... -</programlisting></listitem> - </varlistentry> -</variablelist> - -<variablelist> - <title>Package <code>box.info</code></title> - <para> - The box.info package provides access to information about - server variables -- pid, uptime, version and others. - </para> - - <para> - <emphasis role="strong">recovery_lag</emphasis> holds the - difference (in seconds) between the current time on the - machine (wall clock time) and the time stamp of the last - applied record. In replication setup, this difference can - indicate the delay taking place before a change is - applied to a replica. - </para> - <para> - <emphasis role="strong">recovery_last_update</emphasis> is - the wall clock time of the last change recorded in the - write-ahead log. To convert it to human-readable time, - you can use <command>date -d@<replaceable>1306964594.980</replaceable></command>. - </para> - <para> - <emphasis role="strong">status</emphasis> is - either "primary" or "replica/<hostname>". - </para> - - <varlistentry> - <term> - <emphasis role="lua">box.info()</emphasis> - </term> - <listitem> - <para> - Since box.info contents are dynamic, it's not - possible to iterate over keys with the Lua - <emphasis>pairs()</emphasis> function. For this - purpose, <emphasis>box.info()</emphasis> builds and - returns a Lua table with all keys and values provided - in the package. - </para> - <para> - Returns: (type = Lua table) keys and values in the package. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -tarantool> <userinput>box.info()</userinput> -- server: - lsn: 158 - ro: false - uuid: 75967704-0115-47c2-9d03-bd2bdcc60d64 - id: 1 - pid: 32561 - version: 1.6.4-411-gcff798b - snapshot_pid: 0 - status: running - vclock: {1: 158} - replication: - status: off - uptime: 2778 -...</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua">box.info.status, box.info.pid, box.info.version, ...</emphasis> - </term> - <listitem> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -tarantool> <userinput>box.info.pid</userinput> ---- -- 1747 -... -tarantool> <userinput>box.info.logger_pid</userinput> ---- -- 1748 -... -tarantool> <userinput>box.info.version</userinput> ---- -- 1.6.4-411-gcff798b -... -tarantool> <userinput>box.info.uptime</userinput> ---- -- 3672 -... -tarantool> <userinput>box.info.status</userinput> ---- - - running -... -tarantool> <userinput>box.info.recovery_lag</userinput> ---- - - 0.000 -... -tarantool> <userinput>box.info.recovery_last_update</userinput> ---- - - 1306964594.980 -... -tarantool> <userinput>box.info.snapshot_pid</userinput> ---- - - 0 -... -</programlisting> - </listitem> - </varlistentry> - -</variablelist> - -<variablelist> - <title>Package <code>box.slab</code></title> - <para> - The box.slab package provides access to slab allocator statistics. - The slab - allocator is the main allocator used to store tuples. - This can be used to monitor the total memory use and - memory fragmentation. - </para> - <para> - The display of slabs is broken down by the slab size -- - 64-byte, 136-byte, and so on. The example omits the slabs - which are empty. The example display is saying that: - there are 16 items stored - in the 64-byte slab (and 16*64=1024 so - bytes_used = 1024); there is 1 item - stored in the 136-byte slab (and - 136*1=136 so bytes_used = 136); the - arena_used value is the total of all the bytes_used - values (1024+136 = 1160); the - arena_size value is the arena_used value - plus the total of all the bytes_free values - (1160+4193200+4194088 = 8388448). The - arena_size and arena_used values are the amount of - the % of <olink targetptr="slab_alloc_arena"/> that is - already distributed to the slab allocator. - </para> - <varlistentry> - <term xml:id="box.slab.info" xreflabel="box.slab.info()"> - <emphasis role="lua">box.slab</emphasis></term> - <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting> -tarantool> <userinput>box.slab.info().arena_used</userinput> ---- - - 4194304 -... -tarantool> <userinput>box.slab.info().arena_size</userinput> ---- - - 104857600 -... -tarantool> <userinput>box.slab.info().slabs</userinput> ---- -- - {mem_free: 9320, mem_used: 6976, 'item_count': 109, 'item_size': 64, 'slab_count': 1, - 'slab_size': 16384} - - {mem_free: 16224, mem_used: 72, 'item_count': 1, 'item_size': 72, 'slab_count': 1, - 'slab_size': 16384} - etc. -... -tarantool> <userinput>box.slab.info().slabs[1]</userinput> ---- -- {mem_free: 9320, mem_used: 6976, 'item_count': 109, 'item_size': 64, 'slab_count': 1, - 'slab_size': 16384} -... -</programlisting></listitem> - </varlistentry> -</variablelist> - -<variablelist> - <title>Package <code>box.stat</code></title> - <para> - The box.stat package provides access to request - statistics. Show the average number of requests per second, and the - total number of requests since startup, broken down by - request type. - </para> - <varlistentry> - <term xml:id="box.stat" xreflabel="box.stat"> - <emphasis role="lua">box.stat</emphasis></term> - <listitem><bridgehead renderas="sect4">Example</bridgehead><programlisting> -tarantool> <userinput>box.stat, type(box.stat) -- a virtual table</userinput> ---- -- [] -- table -... -tarantool> <userinput>box.stat() -- the full contents of the table</userinput> ---- -- DELETE: - total: 48902544 - rps: 147 - EVAL: - total: 0 - rps: 0 - SELECT: - total: 388322317 - rps: 1246 - REPLACE: - total: 4 - rps: 0 - INSERT: - total: 48207694 - rps: 139 - AUTH: - total: 0 - rps: 0 - CALL: - total: 8 - rps: 0 - UPDATE: - total: 743350520 - rps: 1874 -... -tarantool> <userinput>box.stat().DELETE -- a selected item of the table</userinput> ---- -- total: 48902544 - rps: 0 -... -</programlisting></listitem> - </varlistentry> -</variablelist> - -<para> - Additional examples can be found in the open source <link - xlink:href="https://github.com/mailru/tntlua">Lua stored - procedures repository</link> and in the server test suite. -</para> -</section> - -<section xml:id="sp-net-box"> - <title>Package <code>net.box</code> — working with networked Tarantool peers</title> - <para> - The <code>net.box</code> package contains connectors to remote database systems. - One variant, <code>box.net.sql</code>, is for connecting to MySQL or MariaDB or PostgreSQL - — that variant is the subject of the <olink targetptr="plugins"><quote>SQL DBMS plugins</quote></olink> appendix. - In this section the subject is the built-in variant, <code>box.net</code>. - This is for connecting to tarantool servers via a network. - </para> -<variablelist xml:id="net.box"> - <para> - Call <code>require('net.box')</code> to get a net.box object, which will be called <code>net_box</code> - for examples in this section. - Call <code><replaceable>net_box</replaceable>:new()</code> to connect and get a connection object, - which will be called <code>conn</code> for examples in this section. - Call the other <code>net.box()</code> routines, passing <code>conn:</code>, - to execute requests on the remote box. - Call <code>conn:close</code> to disconnect. - </para> - - <para> - All <code>net.box</code> methods are fiber-safe, that is, it is - safe to share and use the same connection object across - multiple concurrent fibers. In fact, it's perhaps the - best programming practice with Tarantool. When multiple - fibers use the same connection, all requests are pipelined - through the same network socket, but each fiber gets back a - correct response. Reducing the number of active sockets - lowers the overhead of system calls and increases the - overall server performance. There are, however, cases when - a single connection is not enough — for example when it's necessary to - prioritize requests or to use different authentication ids. - </para> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="net.box.new"> - conn = <replaceable>net_box</replaceable>:new(<replaceable>host</replaceable>, <replaceable>port</replaceable> [, {<replaceable>other parameter[s]</replaceable>}])</emphasis> - </term> - <listitem> - <para> - Create a new connection. The connection is - established on demand, at the time of the first - request. It is re-established automatically after - a disconnect. - The returned <code>conn</code> object supports methods for making remote - requests, such as select, update or delete. - </para> - <para> - For the local tarantool server there is a pre-created always-established - connection object named <code><replaceable>net_box</replaceable>.self</code>. - Its purpose is to make polymorphic use of the - <code>net.box</code> API easier. Therefore - <code>conn = <replaceable>net_box</replaceable>:new('localhost', 3301)</code> can - be replaced by <code>conn = <replaceable>net.box</replaceable>.self</code>. - However, there is an important difference between the embedded - connection and a remote one. With the embedded connection, - requests which do not modify data do not yield. When using - a remote connection, any request can yield, and local database state may - have changed by the time it returns. - </para> - <para> - Parameters: <code>host</code>, <code>port</code>, <code>wait_connect</code>, <code>user</code>, <code>password</code>. - </para> - <para> - Returns: (type = userdata) conn object). - </para> - <para> - Examples: <code><userinput>conn = net_box:new('localhost', 3301)</userinput></code>, - <code><userinput>conn = net_box:new('127.0.0.1', box.cfg.listen, {wait_connect = false, user = 'guest', password = ''})</userinput></code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.ping"> - <replaceable>conn</replaceable>:ping()</emphasis></term> - <listitem> - <para> - Execute a PING command. - </para> - <para> - Returns: (type = boolean) <code>true</code> on success, - <code>false</code> on error. Example: <code><userinput>net_box.self:ping()</userinput></code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.wait_connected"> - <replaceable>conn</replaceable>:wait_connected([<replaceable>timeout</replaceable>])</emphasis></term> - <listitem> - <para> - Wait for connection to be active or closed. - </para> - <para> - Returns: (type = boolean) <code>true</code> when connected, - <code>false</code> on failure. Example: <code><userinput>net_box.self:wait_connected()</userinput></code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.close"> - <replaceable>conn</replaceable>:close()</emphasis></term> - <listitem> - <para> - Close a connection. - </para> - <para> - Connection objects are garbage collected just like any other objects - in Lua, so an explicit destruction is not mandatory. - However, since <code>close()</code> is a system call, it - is good programming practice to close a connection - explicitly when it is no longer needed, to avoid lengthy - stalls of the garbage collector. - </para> - <para> - Example: <code><userinput>conn:close()</userinput></code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.select"> - <replaceable>conn</replaceable>.space.<replaceable>space-name</replaceable>:select{<replaceable>field-value</replaceable>, ...}</emphasis></term> - <listitem> - <para> - <code>conn.space.<replaceable>space-name</replaceable>:select{...}</code> is the remote-call equivalent of the local call - <code xlink:href="#box.select">box.space.<replaceable>space-name</replaceable>:select{...}</code>. - Please note this difference: a local <code>box.space.<replaceable>space-name</replaceable>:select{...}</code> does not yield, - but a remote <code>conn.space.<replaceable>space-name</replaceable>:select{...}</code> call does yield, - so local data may change while a remote <code>conn.space.<replaceable>space-name</replaceable>:select{...}</code> is running. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.insert"> - <replaceable>conn</replaceable>.space.<replaceable>space-name</replaceable>:insert{field-value, ...}</emphasis></term> - <listitem> - <para> - <code>conn.space.<replaceable>space-name</replaceable>:insert(...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.insert">box.space.<replaceable>space-name</replaceable>:insert(...)</code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.replace"> - <replaceable>conn</replaceable>.space.<replaceable>space-name</replaceable>:replace{field-value, ...}</emphasis></term> - <listitem> - <para> - <code>conn.space.<replaceable>space-name</replaceable>:replace(...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.replace">box.space.<replaceable>space-name</replaceable>:replace(...)</code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.update"> - <replaceable>conn</replaceable>.space.<replaceable>space-name</replaceable>:update(<replaceable>key</replaceable>, <replaceable>format</replaceable>, ...)</emphasis></term> - <listitem> - <para> - <code>conn.space.<replaceable>space-name</replaceable>:update(...)</code> is the remote-call equivalent of the local call - <code xlink:href="#box.update">box.space.<replaceable>space-name</replaceable>:update(...)</code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.delete"> - <replaceable>conn</replaceable>.space.<replaceable>space-name</replaceable>:delete{key}</emphasis></term> - <listitem> - <para> - <code>conn.space.<replaceable>space-name</replaceable>:delete{...}</code> is the remote-call equivalent of the local call - <code xlink:href="#box.delete">box.space.<replaceable>space-name</replaceable>:delete{...}</code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.call"> - <replaceable>conn</replaceable>:call(<replaceable>function-name</replaceable> [, <replaceable>arguments</replaceable>])</emphasis></term> - <listitem> - <para> - <code>conn:call('func', '1', '2', '3')</code> is the remote-call equivalent of <code>func('1', '2', '3')</code>. - That is, conn:call is a remote stored-procedure call. - </para> - <para> - Example: <code><userinput>conn:call('function5')</userinput></code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="net.box.timeout"> - <replaceable>conn</replaceable>:timeout(<replaceable>timeout</replaceable>)</emphasis></term> - <listitem> - <para> - <code>timeout(...)</code> is a wrapper which sets a timeout for the request that follows it. - Example: <code>conn:timeout(0.5).space.tester:update({1}, {{'=', 2, 15}})</code>. - </para> - <para> - All remote calls support execution timeouts. - Using a wrapper object makes the remote - connection API compatible with the local one, removing - the need for a separate <code>timeout</code> argument, which - the local version would ignore. Once a request is sent, - it cannot be revoked from the remote server even if - a timeout expires: the timeout expiration only aborts the - wait for the remote server response, not the request itself. - </para> - </listitem> - </varlistentry> -</variablelist> - - <bridgehead renderas="sect4">Example showing use of most of the net.box methods</bridgehead> - <para> - This example will work with the sandbox configuration described in the preface. - That is, there is a space named tester with a numeric primary key. - Assume that the database is nearly empty. - Assume that the tarantool server is running on localhost 127.0.0.1:3301. -<programlisting> -<prompt>tarantool></prompt><userinput> box.schema.user.grant('guest', 'read,write,execute', 'universe')</userinput> ---- -... -<prompt>tarantool></prompt><userinput> console = require('console'); console.delimiter('!')</userinput> ---- -... -<prompt>tarantool></prompt><userinput> net_box = require('net.box')!</userinput> ---- -... -<prompt>tarantool></prompt><userinput> function example()</userinput> -<prompt> ></prompt><userinput> if net_box.self:ping() then</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'self:ping() succeeded')</userinput> -<prompt> ></prompt><userinput> table.insert(ta, ' (no surprise -- self connection is pre-established)')</userinput> -<prompt> ></prompt><userinput> end</userinput> -<prompt> ></prompt><userinput> if box.cfg.listen == '3301' then</userinput> -<prompt> ></prompt><userinput> table.insert(ta,'The local server listen address = 3301')</userinput> -<prompt> ></prompt><userinput> else</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'The local server listen address is not 3301')</userinput> -<prompt> ></prompt><userinput> table.insert(ta, '( (maybe box.cfg{...listen="3301"...} was not stated)')</userinput> -<prompt> ></prompt><userinput> table.insert(ta, '( (so connect will fail)')</userinput> -<prompt> ></prompt><userinput> end</userinput> -<prompt> ></prompt><userinput> conn = net_box:new('127.0.0.1', 3301)</userinput> -<prompt> ></prompt><userinput> conn.space.tester:delete{800}</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'conn delete done on tester.')</userinput> -<prompt> ></prompt><userinput> conn.space.tester:insert{800, 'data'}</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'conn insert done on tester, index 0')</userinput> -<prompt> ></prompt><userinput> table.insert(ta, ' primary key value = 800.')</userinput> -<prompt> ></prompt><userinput> wtuple = conn.space.tester:select{800}</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'conn select done on tester, index 0')</userinput> -<prompt> ></prompt><userinput> table.insert(ta, ' number of fields = ' .. #wtuple)</userinput> -<prompt> ></prompt><userinput> conn.space.tester:delete{800}</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'conn delete done on tester')</userinput> -<prompt> ></prompt><userinput> conn.space.tester:replace{800, 'New data', 'Extra data'}</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'conn:replace done on tester')</userinput> -<prompt> ></prompt><userinput> conn:timeout(0.5).space.tester:update({800}, {{'=', 2, 'Fld#1'}})</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'conn update done on tester')</userinput> -<prompt> ></prompt><userinput> conn:close()</userinput> -<prompt> ></prompt><userinput> table.insert(ta, 'conn close done')</userinput> -<prompt> ></prompt><userinput> end!</userinput> ---- -... -<prompt>tarantool></prompt><userinput> console.delimiter('')!</userinput> ---- -... -<prompt>tarantool></prompt><userinput> ta = {}</userinput> ---- -... -<prompt>tarantool></prompt><userinput> example()</userinput> ---- -... -<prompt>tarantool></prompt><userinput> ta</userinput> ---- -- - self:ping() succeeded - - ' (no surprise -- self connection is pre-established)' - - The local server listen address = 3301 - - conn delete done on tester. - - conn insert done on tester, index 0 - - ' primary key value = 800.' - - conn select done on tester, index 0 - - ' number of fields = 1' - - conn delete done on tester - - conn:replace done on tester - - conn update done on tester - - conn close done -... -<prompt>tarantool></prompt><userinput> box.space.tester:select{800} -- Prove that the update succeeded.</userinput> ---- -- [800, 'Fld#1', 'Extra data'] -... -</programlisting> -</para> -</section> - - -<section xml:id="administrative-requests"> - <title>Administrative requests</title> - <para>To learn which functions are considered to be administrative, - type <emphasis role="lua">help()</emphasis>. - A reference description also follows - below:</para> - - <variablelist> - - <varlistentry> - <term xml:id="box.snapshot" xreflabel="box.snapshot()"> - <emphasis role="lua">box.snapshot()</emphasis> - </term> - <listitem><para> - Take a snapshot of all data and store it in - <filename><olink - targetptr="snap_dir"/>/<latest-lsn>.snap</filename>. - To take a snapshot, Tarantool first enters the delayed - garbage collection mode for all data. In this mode, - tuples which were allocated before the snapshot has - started are not freed until the snapshot has finished. - To preserve consistency of the primary key, used to - iterate over tuples, a copy-on-write technique is employed. - If the master process changes part of a primary key, - the corresponding process page is split, and the snapshot - process obtains an old copy of the page. Since a - snapshot is written sequentially, one can expect a very - high write performance (averaging to 80MB/second on modern - disks), which means an average database instance gets - saved in a matter of minutes. Note, that as long as there - are any changes to the parent index memory through concurrent - updates, there are going to be page splits, and therefore - one needs to have some extra free memory to run this - command. 10% of <olink targetptr="slab_alloc_arena"/> - is, on average, sufficient. This statement waits until a - snapshot is taken and returns operation result. For - example: -<programlisting>tarantool> <userinput>box.info.version</userinput> ---- -- 1.6.3-439-g7e1011b -... -tarantool> <userinput>box.snapshot()</userinput> ---- -- ok -... -tarantool> <userinput>box.snapshot()</userinput> ---- -error: can't save snapshot, errno 17 (File exists) -... -</programlisting> - </para> - <para> - Taking a snapshot does not cause the server to start a new - write-ahead log. Once a snapshot is taken, old WALs can be - deleted as long as all replicas are up to date. But the - WAL which was current at the time <emphasis - role="lua">box.snapshot()</emphasis> started must be - kept for recovery, since it still contains log records - written after the start of <emphasis role="lua"> - box.snapshot()</emphasis>. - </para> - <para> - An alternative way to save a snapshot is to send the server - SIGUSR1 UNIX signal. While this approach could be handy, it - is not recommended for use in automation: a signal provides no - way to find out whether the snapshot was taken successfully - or not. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="coredump" xreflabel="coredump()"> - <emphasis role="lua">coredump()</emphasis> - </term> - <listitem><para> - Fork and dump a core. Since Tarantool stores all tuples - in memory, it can take some time. Mainly useful for - debugging. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="fiber.info" xreflabel="fiber.info"> - <emphasis role="lua">require('fiber').info()</emphasis> - </term> - <listitem><para> - Show all running fibers, with their stack. - Mainly useful for debugging. - </para></listitem> - </varlistentry> - - </variablelist> - -</section> - - -<section xml:id="multitasking"> -<title>Atomic execution</title> - -<para> - In several places it's been noted that Lua processes occur in - fibers on a single thread. That is why there - can be a guarantee of execution atomicity. That requires emphasis. -</para> -<bridgehead renderas="sect4">Cooperative multitasking environment</bridgehead> -<para> - Tarantool core is built around a cooperative multi-tasking - paradigm: unless a running fiber deliberately yields control - to some other fiber, it is not preempted. - <quote>Yield points</quote> are built into all - calls from Tarantool core to the operating system. - Any system call which can block is performed in an - asynchronous manner and the fiber waiting - on the system call is preempted with a fiber ready to - run. This model makes all programmatic locks unnecessary: - cooperative multitasking ensures that there is no concurrency - around a resource, no race conditions and no memory - consistency issues. -</para> -<para> - When requests are small, e.g. simple UPDATE, INSERT, DELETE, - SELECT, fiber scheduling is fair: it takes only a little time - to process the request, schedule a disk write, and yield to - a fiber serving the next client. -</para> -<para> - A function, however, can perform complex computations, - or be written in such a way that control is not given away for a - long time. This can lead to unfair scheduling, when a single - client throttles the rest of the system, or to apparent stalls - in request processing. - Avoiding this situation is the responsibility of the function's - author. Most of the <code>box</code> calls, such as - <code>box.space...insert</code>, <code>box.space...update</code>, - <code>box.space...delete</code> are yield points; - <code>box.space...select</code>, however, is not. -</para> -<para> - It should also be noted that, in the absence of transactions, - any yield in a function is a potential change in the - database state. Effectively, it's only possible - to have CAS (compare-and-swap) -like atomic stored - procedures: i.e. functions which select and then modify a record. - Multiple data change requests always run through a built-in - yield point. -</para> -<para> - At this point an objection could arise: "It's good that a single - data-change request will commit and yield, but surely there are - times when multiple data-change requests must happen without - yielding." The standard example is the money-transfer, where - $1 is withdrawn from account #1 and deposited into account #2. - If something interrupted after the withdrawal, then the - institution would be out of balance. For such cases, the - <code>begin ... commit|rollback</code> block was designed. -</para> - <variablelist> - <varlistentry> - <term xml:id="begin" xreflabel="begin()"> - <emphasis role="lua">box.begin()</emphasis> - </term> - <listitem><para> - From this point, implicit yields are suspended. - In effect the fiber which executes <code>box.begin()</code> - is starting an "active multi-request transaction", blocking all - other fibers until the transaction ends. - All operations within this transaction should use the same storage engine. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="commit" xreflabel="commit()"> - <emphasis role="lua">box.commit()</emphasis> - </term> - <listitem><para> - End the currently active transaction, and make - all its data-change operations permanent. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="rollback" xreflabel="rollback()"> - <emphasis role="lua">box.rollback()</emphasis> - </term> - <listitem><para> - End the currently active transaction, but cancel - all its data-change operations. An explicit call - to functions outside box.space that always yield, - such as <code>fiber.yield</code> or - <code>fiber.sleep</code>, will have the same effect. - </para></listitem> - </varlistentry> - </variablelist> -<para> - <emphasis>The requests in a transaction must be - sent to the server as a single block.</emphasis> - It is not enough to enclose them - between <code>begin</code> and <code>commit</code> - or <code>rollback</code>. To ensure they are sent - as a single block: put them in a function, or put - them all on one line, or use a delimiter so that - multi-line requests are handled together. -</para> - -<para> -Example: -Assuming that in tuple set 'tester' there are tuples -in which the third field represents a positive dollar amount ... -Start a transaction, withdraw from tuple#1, deposit in tuple#2, -and end the transaction, making its effects permanent.<programlisting> -console = require('console'); console.delimiter('!') -box.begin() -amount_of_money = 1.00 -box.space.tester:update({999}, {{'-', 3, amount_of_money}}) -box.space.tester:update({1000}, {{'+', 3, amount_of_money}}) -box.commit() -console.delimiter('')!</programlisting> -</para> -</section> - - -<section xml:id="authentication" xreflabel="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 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: -the numeric id of the tuple, the numeric id of the tuple's creator, the user name, the type, and the optional password. -</para> - -<para> -There are three special tuples in the _user space: 'guest', 'admin', and 'public'. -</para> - - - <table> - <title>The system users</title> - <tgroup cols="4" align="left" colsep="1" rowsep="1"> - <tbody> - <row> - <entry>NAME</entry><entry>ID</entry><entry>TYPE</entry><entry>DESCRIPTION</entry> - </row> - <row> - <entry>guest</entry><entry>0</entry><entry>user</entry><entry>Default when connecting remotely. Usually an untrusted user with few privileges.</entry> - </row> - <row> - <entry>admin</entry><entry>1</entry><entry>user</entry><entry>Default when using <code>tarantool</code> as a console. Usually an administrative user with all privileges.</entry> - </row> - <row> - <entry>public</entry><entry>2</entry><entry>role</entry><entry>Not a user in the usual sense. Described later in section <link linkend="roles">Roles</link>. </entry> - </row> - </tbody> - </tgroup> - </table> - - -<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, which by default has no password: -<programlisting><prompt>tarantool></prompt> <userinput>box.space._user:select{0}</userinput> ---- -- - [0, 1, 'guest', 'user'] -...</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>. -The form -<code>box.schema.user.create(<replaceable>user-name</replaceable>, {password=<replaceable>password</replaceable>})</code> -is better because in a <link linkend="URI">URI</link> (Uniform Resource Identifier) it is usually illegal to include a user-name without a password. -</para> - -<para> -To change the current user's password, say -<code>box.schema.user.passwd(<replaceable>password</replaceable>)</code>. -</para> - -<para> -To change a different user's password, say -<code>box.schema.user.passwd(<replaceable>user-name</replaceable>, <replaceable>password</replaceable>)</code>. -(Only the admin user can perform this function.) -</para> - -<para> -To drop a user, say -<code>box.schema.user.drop(<replaceable>user-name</replaceable>)</code>. -</para> - -<para> -To check whether a user exists, say -<code>box.schema.user.exists(<replaceable>user-name</replaceable>)</code>, -which returns <code>true</code> or <code>false</code>. -</para> - -<para> -For example, here is a session which creates a new user with -a strong password, selects a tuple in -the _user space, and then drops the user. -<programlisting><prompt>tarantool></prompt> <userinput>box.schema.user.create('JeanMartin', {password = 'Iwtso_6_os$$'})</userinput> ---- -... - -<prompt>tarantool></prompt> <userinput>box.space._user.index.name:select{'JeanMartin'}</userinput> ---- -- - [17, 1, 'JeanMartin', 'user', {'chap-sha1': 't3xjUpQdrt857O+YRvGbMY5py8Q='}] -... - -<prompt>tarantool></prompt> <userinput>box.schema.user.drop('JeanMartin')</userinput> ---- -...</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> -or -<code>box.schema.user.revoke(<replaceable>user-name-of-grantee</replaceable>, <replaceable>operation-type</replaceable>, 'universe')</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> <userinput>box.schema.user.grant('guest', 'read', 'space', 'space55')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>box.schema.user.revoke('guest', 'read', 'space', 'space55')</userinput> ---- -...</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> -The function for checking whether a _func tuple exists is: -<code>box.schema.func.exists(<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> <userinput>function f7() box.session.uid() end</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>box.schema.func.create('f7')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>box.schema.user.grant('guest', 'execute', 'function', 'f7')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>box.schema.user.revoke('guest', 'execute', 'function', 'f7')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>box.schema.func.drop('f7')</userinput> ---- -...</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> - -<para> -If a user types requests directly on the Tarantool server in its interactive mode, -or if a user connects via telnet to the administrative port (using -<olink targetptr="admin_port">admin</olink> instead of listen), then the user by default is 'admin' and has -many privileges. If a user connects from an application program via one of the -<olink targetptr="connectors">connectors</olink>, then the user by default is 'guest' and has few -privileges. Typically an admin user will set up and configure objects, then -grant privileges to appropriate non-admin users. Typically a guest user will -use <code>box.session.su()</code> to change into a non-generic user to whom admin -has granted more than the default privileges. For example, admin might say:<programlisting> -box.space._user:insert{123456,0,'manager'} -box.schema.user.grant('manager', 'read', 'space', '_space') -box.schema.user.grant('manager', 'read', 'space', 'payroll')</programlisting> -and later a guest user, who wishes to see the payroll, might say:<programlisting> -box.session.su('manager') -box.space.payroll:select{'Jones'}</programlisting> -</para> - -<para xml:id="roles"> -<bridgehead renderas="sect4">Roles</bridgehead> -A role is a container for privileges which can be granted to regular users. -Instead of granting and revoking individual privileges, one can put all the -privileges in a role and then grant or revoke the role. -Role information is in the _user space but the third field -- the type field -- is 'role' rather than 'user'. -</para> - -<para> -If a role R1 is granted a privilege X, and user U1 is granted a privilege "role R1", -then user U1 in effect has privilege X. -Then if a role R2 is granted a privilege Y, and role R1 is granted a privilege "role R2", -then user U1 in effect has both privilege X and privilege Y. -In other words, a user gets all the privileges that are granted to a user's roles, -directly or indirectly. -</para> - -<variablelist> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-1">box.schema.role.create(<replaceable>role-name</replaceable>)</emphasis></term> - <listitem><para> - Create a new role. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-2">box.schema.role.grant(<replaceable>role-name</replaceable>, <replaceable>privilege</replaceable>)</emphasis></term> - <listitem><para> - Put a privilege in a role. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-3">box.schema.role.revoke(<replaceable>role-name</replaceable>, <replaceable>privilege</replaceable>)</emphasis></term> - <listitem><para> - Take a privilege out of a role. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-4">box.schema.user.drop(<replaceable>role-name</replaceable>)</emphasis></term> - <listitem><para>Drop a role. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-5">box.schema.role.info()</emphasis></term> - <listitem><para>Get information about a role. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-6">box.schema.user.grant(<replaceable>user-name</replaceable>, 'execute', 'role', <replaceable>role-name</replaceable>)</emphasis></term> - <listitem><para>Grant a role to a user. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-7">box.schema.role.grant(<replaceable>role-name</replaceable>, 'execute', 'role', <replaceable>role-name</replaceable>)</emphasis></term> - <listitem><para>Grant a role to a role. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-8">box.schema.user.revoke(<replaceable>user-name</replaceable>, 'execute', 'role', <replaceable>role-name</replaceable>)</emphasis></term> - <listitem><para>Revoke a role from a user. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-9">box.schema.role.revoke(<replaceable>role-name</replaceable>, 'execute', 'role', <replaceable>role-name</replaceable>)</emphasis></term> - <listitem><para>Revoke a role from a role. - </para></listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua" xml:id="role-a">box.schema.role.exists(<replaceable>role-name</replaceable>)</emphasis></term> - <listitem><para>Check whether a role exists. Returns (type = boolean) <code>true</code> if role-name identifies a role, otherwise <code>false</code>. - </para></listitem> - </varlistentry> - -</variablelist> - -<para> -There is one predefined role, named 'public', which is automatically assigned to -new users when they are created with <code>box.schema.user.create(<replaceable>user-name</replaceable>)</code>. -Therefore a convenient way to grant 'read' on space 't' to every user that will ever exist is: -<code>box.schema.role.grant('public','read','space','t')</code>. -</para> - -<para> -<bridgehead renderas="sect4">Example showing a role within a role</bridgehead> -In this example, a new user named U1 will insert a new tuple into -a new space named T, and will succeed even though user U1 has no -direct privilege to do such an insert -- that privilege is inherited -from role R1, which in turn inherits from role R2. -<programlisting> --- This example will work for a user with many privileges, such as 'admin' -box.schema.space.create('T') -box.space.T:create_index('primary',{}) --- Create a user U1 so that later it's possible to say box.session.su('U1') -box.schema.user.create('U1') --- Create two roles, R1 and R2 -box.schema.role.create('R1') -box.schema.role.create('R2') --- Grant role R2 to role R1 and role R1 to U1 (order doesn't matter) -box.schema.role.grant('R1','execute','role','R2') -box.schema.role.grant('U1','execute','role','R1') --- Grant read and execute privileges to R2 (but not to R1 and not to U1) -box.schema.role.grant('R2','read,write','space','T') -box.schema.role.grant('R2','execute','universe') --- Use box.session.su to say "now become user U1" -box.session.su('U1') --- The following insert succeeds because U1 in effect has write privilege on T -box.space.T:insert{1} -</programlisting> -</para> - -</section> - -<section xml:id="limitations"> - -<title>Limitations</title> - -<variablelist> - - <varlistentry> - <term xml:id="limitations-index-field-count" xreflabel="limitations-index-field-count">Number of fields in an index</term> - <listitem><para>For BITSET indexes, the maximum is 1. - For TREE or HASH indexes, the maximum is 255 (box.schema.INDEX_PART_MAX). - For RTREE indexes, the number of fields must be either 2 or 4. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-index-count" xreflabel="limitations-index-count">Number of indexes in a space</term> - <listitem><para>10 (box.schema.INDEX_MAX). - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-tuple-field-count" xreflabel="limitations-tuple-field-count">Number of fields in a tuple</term> - <listitem><para>The theoretical maximum is 2147483647 (box.schema.FIELD_MAX). - The practical maximum is whatever is specified by the space's <link linkend="box.space.field_count">field_count</link> member, - or the maximum tuple length. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-space-count" xreflabel="limitations-space-count">Number of spaces</term> - <listitem><para>The theoretical maximum is 2147483647 (box.schema.SPACE_MAX). - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-connections-count" xreflabel="limitations-connections-count">Number of connections</term> - <listitem><para>The practical limit is the number of file descriptors that one can set with - the operating system. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-slab-alloc-arena-size" xreflabel="limitations-slab-alloc-arena-size">Space size</term> - <listitem><para>The total maximum size for all spaces is in effect set by <olink targetptr="slab_alloc_arena"/>, - which in turn is limited by the total available memory. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-update-count" xreflabel="limitations-update-count">Update operations count</term> - <listitem><para>The maximum number of operations that can be in a single update is 4000 (BOX_UPDATE_OP_CNT_MAX). - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-user-count" xreflabel="limitations-user-count">Number of users and roles</term> - <listitem><para>32. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-name-length" xreflabel="limitations-name-length">Length of an index name or space name or user name</term> - <listitem><para>32 (box.schema.NAME_MAX). - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="sophia-limitations" xreflabel="sophia-limitations">Limitations which are only applicable for the sophia storage engine</term> - <listitem><para> - The maximum number of fields in an index is always 1, that is, multi-part indexes are not supported. - The maximum number of indexes in a space is always 1, that is, secondary indexes are not supported. - Indexes must be unique, that is, the options type=HASH or type=RTREE or type=BITSET are not supported. - Indexes must be unique, that is, the option unique=false is not supported. - The alter(), len(), and count() functions are not supported. - </para></listitem> - </varlistentry> - -</variablelist> - -</section> - - -</chapter> -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/errcode.xml b/doc/user/errcode.xml deleted file mode 100644 index 792393d55a434dee2e63b795d6d15068f62eb49a..0000000000000000000000000000000000000000 --- a/doc/user/errcode.xml +++ /dev/null @@ -1,97 +0,0 @@ -<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="errcode"> - -<title>List of error codes</title> - -<para>In the current version of the binary protocol, error message, -which is normally more descriptive than error code, -is not present in server response. The actual message may contain -a file name, a detailed reason or operating system error code. -All such messages, however, are logged in the error log. -Below follow only general descriptions -of some popular codes. A complete list of errors can be found in -file <filename xlink:href="https://github.com/tarantool/tarantool/blob/master/src/errcode.h">errcode.h</filename> in the source tree. - -</para> -<variablelist> -<title>List of error codes</title> - - <varlistentry> - <term xml:id="ER_NONMASTER" xreflabel="ER_NONMASTER">ER_NONMASTER</term> - <listitem><para>Can't modify data on a replication slave. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_ILLEGAL_PARAMS" xreflabel="ER_ILLEGAL_PARAMS">ER_ILLEGAL_PARAMS</term> - <listitem><para>Illegal parameters. Malformed protocol - message. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_MEMORY_ISSUE" xreflabel="ER_MEMORY_ISSUE">ER_MEMORY_ISSUE</term> - <listitem><para>Out of memory: <olink targetptr="slab_alloc_arena"/> limit is reached. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_WAL_IO" xreflabel="ER_WAL_IO">ER_WAL_IO</term> - <listitem><para>Failed to write to disk. May mean: failed to record a change in - the write-ahead log. Some sort of disk error. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_KEY_PART_COUNT" xreflabel="ER_KEY_PART_COUNT">ER_KEY_PART_COUNT</term> - <listitem><para>Key part count is not the same as index part count - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_NO_SUCH_SPACE" xreflabel="ER_NO_SUCH_SPACE">ER_NO_SUCH_SPACE</term> - <listitem><para>Attempt to access a space that does not exist. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_NO_SUCH_INDEX" xreflabel="ER_NO_SUCH_INDEX">ER_NO_SUCH_INDEX</term> - <listitem><para>The specified index does not exist for the specified space. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_PROC_LUA" xreflabel="ER_PROC_LUA">ER_PROC_LUA</term> - <listitem><para>An error inside a Lua procedure. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_FIBER_STACK" xreflabel="ER_FIBER_STACK">ER_FIBER_STACK</term> - <listitem><para>Recursion limit reached when creating a new fiber. This is - usually an indicator of a bug in a stored procedure, recursively invoking itself - ad infinitum. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_UPDATE_FIELD" xreflabel="ER_UPDATE_FIELD">ER_UPDATE_FIELD</term> - <listitem><para>An error occurred during update of a field. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="ER_TUPLE_FOUND" xreflabel="ER_TUPLE_FOUND">ER_TUPLE_FOUND</term> - <listitem><para>.Duplicate key exists in unique index ... - </para></listitem> - </varlistentry> - -</variablelist> - -</appendix> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/html-highlight.xsl b/doc/user/html-highlight.xsl deleted file mode 100644 index 02cb8b611b8213911cc5707cdf7f92d3472e0588..0000000000000000000000000000000000000000 --- a/doc/user/html-highlight.xsl +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="ASCII"?> -<!--This file was created automatically by html2xhtml--> -<!--from the HTML stylesheets.--> -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:d="http://docbook.org/ns/docbook" -xmlns:xslthl="http://xslthl.sf.net" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xslthl d" version="1.0"> - -<!-- ******************************************************************** - $Id: highlight.xsl 8419 2009-04-29 20:37:52Z kosek $ - ******************************************************************** - - This file is part of the XSL DocBook Stylesheet distribution. - See ../README or http://docbook.sf.net/release/xsl/current/ for - and other information. - - ******************************************************************** --> - -<xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/highlighting/common.xsl"/> - -<xsl:template match="xslthl:keyword" mode="xslthl"> - <b class="hl-keyword"><xsl:apply-templates mode="xslthl"/></b> -</xsl:template> - -<xsl:template match="xslthl:string" mode="xslthl"> - <b class="hl-string"><i style="color:red"><xsl:apply-templates mode="xslthl"/></i></b> -</xsl:template> - -<xsl:template match="xslthl:comment" mode="xslthl"> - <i class="hl-comment" style="color: silver"><xsl:apply-templates mode="xslthl"/></i> -</xsl:template> - -<xsl:template match="xslthl:directive" mode="xslthl"> - <span class="hl-directive" style="color: maroon"><xsl:apply-templates mode="xslthl"/></span> -</xsl:template> - -<xsl:template match="xslthl:tag" mode="xslthl"> - <b class="hl-tag" style="color: #000096"><xsl:apply-templates mode="xslthl"/></b> -</xsl:template> - -<xsl:template match="xslthl:attribute" mode="xslthl"> - <span class="hl-attribute" style="color: #F5844C"><xsl:apply-templates mode="xslthl"/></span> -</xsl:template> - -<xsl:template match="xslthl:value" mode="xslthl"> - <span class="hl-value" style="color: #993300"><xsl:apply-templates mode="xslthl"/></span> -</xsl:template> - -<xsl:template match="xslthl:html" mode="xslthl"> - <b><i style="color: red"><xsl:apply-templates mode="xslthl"/></i></b> -</xsl:template> - -<xsl:template match="xslthl:xslt" mode="xslthl"> - <b style="color: #0066FF"><xsl:apply-templates mode="xslthl"/></b> -</xsl:template> - -<!-- Not emitted since XSLTHL 2.0 --> -<xsl:template match="xslthl:section" mode="xslthl"> - <b><xsl:apply-templates mode="xslthl"/></b> -</xsl:template> - -<xsl:template match="xslthl:number" mode="xslthl"> - <span class="hl-number"><xsl:apply-templates mode="xslthl"/></span> -</xsl:template> - -<xsl:template match="xslthl:annotation" mode="xslthl"> - <i><span class="hl-annotation" style="color: gray"><xsl:apply-templates mode="xslthl"/></span></i> -</xsl:template> - -<!-- Not sure which element will be in final XSLTHL 2.0 --> -<xsl:template match="xslthl:doccomment|xslthl:doctype" mode="xslthl"> - <b class="hl-tag" style="color: blue"><xsl:apply-templates mode="xslthl"/></b> -</xsl:template> - -</xsl:stylesheet> diff --git a/doc/user/iterator-types.xml b/doc/user/iterator-types.xml deleted file mode 100644 index 5704cc65f18e1cfa036d24becd71e239372eedb9..0000000000000000000000000000000000000000 --- a/doc/user/iterator-types.xml +++ /dev/null @@ -1,371 +0,0 @@ -<!DOCTYPE para [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<para xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xi="http://www.w3.org/2001/XInclude" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="iterator-types"> - - -<table frame='all' pgwide='1'> -<title>TREE iterator types</title> - -<tgroup cols='3' colsep='1' rowsep='1'> -<colspec colnum='3' colname="Description" colwidth="6*"/> - -<thead> - <row> - <entry>Type</entry> - <entry>Arguments</entry> - <entry>Description</entry> - </row> -</thead> - -<tbody> - - <row> - <entry>box.index.ALL or 'ALL'</entry> - <entry>none</entry> - <entry> - Iterate over all tuples in an index. - Tuples are returned in ascending - order of the key. - </entry> - </row> - - <row> - <entry>box.index.EQ or 'EQ'</entry> - <entry>field values</entry> - <entry> - <simpara> - Equality iterator: iterate over all tuples - where field values = key values. - Parts of a multi-part key need to be separated by - commas. - </simpara> - <simpara> - If the number of field values is less than the - number of parts of a multi-part key, the - missing field values are considered to be matching. - </simpara> - <simpara> - If there are multiple matches, then tuples are - returned in ascending order by key. - </simpara> - </entry> - </row> - - <row> - <entry>box.index.GT or 'GT'</entry> - <entry>field values</entry> - <entry> - Keys match if key values are greater than field values. - If the number of field values is less than the - number of parts of a multi-part key, the - missing field values are considered to be matching. - If the field value is <code>nil</code>, iteration starts from - the smallest key in the index. Tuples are returned - in ascending order by key. - </entry> - </row> - - <row> - <entry>box.index.REQ or 'REQ'</entry> - <entry>field values</entry> - <entry> - Reverse equality iterator. Matching is determined - in the same way as for <code>box.index.EQ</code>, - but, if there are multiple matches, then tuples - are returned in descending order by key, - </entry> - </row> - - <row> - <entry>box.index.GE or 'GE'</entry> - <entry>field values</entry> - <entry> - Keys match if key values are greater than or equal - to field values. - Tuples are returned in ascending order by key. - If the field value is - <code>nil</code>, iteration starts from the first - key in the index. - </entry> - </row> - - <row> - <entry>box.index.LT or 'LT'</entry> - <entry>field values</entry> - <entry> - Keys match if key values are less than - field values. - Tuples are returned in descending order by key. - If the field value is - <code>nil</code>, iteration starts from the last - key in the index. - </entry> - </row> - - <row> - <entry>box.index.LE or 'LE'</entry> - <entry>field values</entry> - <entry> - Keys match if key values are less than or equal - to field values. - Tuples are returned in descending order by key. - If the field value is - <code>nil</code>, iteration starts from the last - key in the index. - </entry> - </row> -</tbody> -</tgroup> -</table> - - -<table frame='all' pgwide='1'> -<title>HASH iterator types</title> - -<tgroup cols='3' colsep='1' rowsep='1'> -<colspec colnum='3' colname="Description" colwidth="6*"/> - -<thead> - <row> - <entry>Type</entry> - <entry>Arguments</entry> - <entry>Description</entry> - </row> -</thead> - -<tbody> - - <row> - <entry>box.index.ALL or 'ALL'</entry> - <entry>none</entry> - <entry> - Iterate over all tuples in an index. - Tuples are returned in ascending - order of the key's hash, and so - will appear to be unordered. - </entry> - </row> - - <row> - <entry>box.index.EQ or 'EQ'</entry> - <entry>field values</entry> - <entry> - <simpara> - Equality iterator: iterate over all tuples matching - the key. - Parts of a multi-part key need to be separated by - commas. - </simpara> - <simpara> - A HASH index only supports exact match: all parts - of a key participating in the index must be provided. - </simpara> - <simpara> - HASH indexes are always unique. - </simpara> - </entry> - </row> - - <row> - <entry>box.index.GT or 'GT'</entry> - <entry>field values</entry> - <entry> - Keys match if hashed key values are greater than hashed field values. - If the number of field values is less than the - number of parts of a multi-part key, the result is an error. - Tuples are returned in ascending order by hashed key, - so the order will appear to be random. - Provided that the space is not being updated, - the 'GT' iterator can be used - to retrieve all tuples piece by piece, - by supplying the last returned value from the previous range as the - start field value for an iterator over the next range. - </entry> - </row> - -</tbody> -</tgroup> -</table> - - -<table frame='all' pgwide='1'> -<title>BITSET iterator types</title> - -<tgroup cols='3' colsep='1' rowsep='1'> -<colspec colnum='3' colname="Description" colwidth="6*"/> - -<thead> - <row> - <entry>Type</entry> - <entry>Arguments</entry> - <entry>Description</entry> - </row> -</thead> - -<tbody> - - <row> - <entry>box.index.ALL or 'ALL'</entry> - <entry>none</entry> - <entry> - Iterate over all tuples in an index. - Tuples are returned in ascending - order of the key's bitset, and so - will appear to be unordered. - </entry> - </row> - - <row> - <entry>box.index.EQ or 'EQ'</entry> - <entry>field values</entry> - <entry> - <simpara> - Equality iterator: iterate over all tuples matching - the field values. - If there are multiple field values, they need to be separated by - commas. - </simpara> - <simpara> - BITSET indexes are always unique. - </simpara> - </entry> - </row> - - <row> - <entry>box.index.BITS_ALL_SET</entry> - <entry>bit mask</entry> - <entry> - Keys match if all of the bits specified in 'bit mask' - are set. - </entry> - </row> - - <row> - <entry>box.index.BITS_ANY_SET</entry> - <entry>bit mask</entry> - <entry> - Keys match if any of the bits specified in 'bit mask' - is set. - </entry> - </row> - - <row> - <entry>box.index.BITS_ALL_NOT_SET</entry> - <entry>bit mask</entry> - <entry> - Keys match if none of the bits specified in 'bit mask' - is set. - </entry> - </row> -</tbody> -</tgroup> -</table> - -<table xml:id="rtree-iterator" frame='all' pgwide='1'> -<title>RTREE iterator types</title> - -<tgroup cols='3' colsep='1' rowsep='1'> -<colspec colnum='3' colname="Description" colwidth="6*"/> - -<thead> - <row> - <entry>Type</entry> - <entry>Arguments</entry> - <entry>Description</entry> - </row> -</thead> - -<tbody> - - <row> - <entry>box.index.ALL or 'ALL'</entry> - <entry>none</entry> - <entry> - All keys match. - Tuples are returned in ascending - order of the primary key. - </entry> - </row> - - <row> - <entry>box.index.EQ or 'EQ'</entry> - <entry>field values</entry> - <entry> - Keys match if the rectangle defined by the field values - is the same as the rectangle defined by the key -- - where "key" means "the key in the RTREE index" and - "rectangle" means "rectangle as explained in section - <link linkend="RTREE">RTREE</link>. - </entry> - </row> - - <row> - <entry>box.index.GT or 'GT'</entry> - <entry>field values</entry> - <entry> - Keys match if all points of the rectangle defined by the field values - are within the rectangle defined by the key. - </entry> - </row> - - <row> - <entry>box.index.GE or 'GE'</entry> - <entry>field values</entry> - <entry> - Keys match if all points of the rectangle defined by the field values - are within, or at the side of, the rectangle defined by the key. - </entry> - </row> - - <row> - <entry>box.index.LT or 'LT'</entry> - <entry>field values</entry> - <entry> - Keys match if all points of the rectangle defined by the key - are within the rectangle defined by the field values. - </entry> - </row> - - <row> - <entry>box.index.LE or 'LE'</entry> - <entry>field values</entry> - <entry> - Keys match if all points of the rectangle defined by the key - are within, or at the side of, the rectangle defined by the field values. - </entry> - </row> - - <row> - <entry>box.index.OVERLAPS or 'OVERLAPS'</entry> - <entry>field values</entry> - <entry> - Keys match if any point of the rectangle defined by the field values - is within, or at the side of, the rectangle defined by the key. - </entry> - </row> - - <row> - <entry>box.index.NEIGHBOR or 'NEIGHBOR'</entry> - <entry>field values</entry> - <entry> - All keys match. Tuples are returned in order according to the - distance from the top left corner of the rectangle - defined by the field values. - </entry> - </row> - -</tbody> -</tgroup> -</table> - -</para> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/language-reference.xml b/doc/user/language-reference.xml deleted file mode 100644 index 067317b8eb8f4d1b472ed5f1b992fa1691a2daf3..0000000000000000000000000000000000000000 --- a/doc/user/language-reference.xml +++ /dev/null @@ -1,363 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:xi="http://www.w3.org/2001/XInclude" - xml:id="language-reference"> - -<title>Language reference</title> -<blockquote><para> - This chapter provides a reference of Tarantool data operations - and administrative commands. -</para></blockquote> -<bridgehead renderas="sect2">Digression: primary and administrative ports</bridgehead> -<para> - During start up, the server can allow connections on up to two TCP ports: - <itemizedlist> - <listitem><para> - Primary port. This port is for handling requests in the - <link xlink:href="http://tarantool.org/doc/box-protocol.html" xlink:title="A complete BNF of Tarantool client/server protocol">native Tarantool protocol</link> - (also called the "binary protocol"), and provides full data access. - </para> - <para> - The default value of the port is <literal>3301</literal>, - as defined in the <olink targetptr="primary_port"/> - configuration option. - </para></listitem> - <listitem><para> - Administrative port, which is for handling requests in unconverted text (also called the "text protocol"), - which defaults to <literal>3313</literal>, - and is defined in the <olink targetptr="admin_port"/> - configuration option. - </para></listitem> - </itemizedlist> - Traditionally, in the absence of authentication, - ordinary users could be blocked from - doing administrative operations by simply having them - blocked from access to the administrative port. - The client, however, had to be aware of - the separation, and the <command>tarantool</command> command line - client automatically selected the correct port - with the help of a simple regular expression. SELECTs, UPDATEs, - INSERTs, DELETEs and CALLs were sent to the primary port. - Lua commands were sent to the administrative port. -</para> - -<section xml:id="data-manipulation"> - <title>Data manipulation</title> - - <para> - The four basic "data-manipulation" requests are: insert() / replace(), - update(), delete(), select(). They all, including - insert() and update() and delete(), may return data. - There are other request types for scanning multiple keys. - </para> - <para> - The update() function supports operations on fields — - assignment, arithmetic operations (the field must be numeric), - cutting and pasting fragments of a field, — as well as - operations on a tuple: push and pop of a field at the tail of - a tuple, deletion and insertion of a field. Multiple - operations can be combined into a single update, and in this - case they are performed atomically. Each operation expects - field number as its first argument. When a sequence of changes - is present, field identifier in each operation is assumed to - be relative to the most recent state of the tuple, i.e. as if - all previous operations in a multi-operation update have - already been applied. In other words, it's always safe to - merge multiple update() invocations into a single one, with no - change in semantics. - </para> - <para>Tarantool protocol was designed with focus on asynchronous - I/O and easy integration with proxies. Each client - request starts with a 12-byte binary header, containing three - fields: request type, length, and a numeric id. - </para> - <para> - The mandatory length, present in request header simplifies - client or proxy I/O. A response to a request is sent to the - client as soon as it is ready. It always carries in its header - the same type and id as in the request. The id makes it - possible to match a request to a response, even if the latter - arrived out of order. - </para> - <para>For the insert() and update() and delete() operations, - it is mandatory to pass the primary-key value. - For the select() operation, either a primary-key value or a - secondary-key value (possibly multi-part) may be passed. - All the data-manipulation functions operate on whole tuple(s), - except update() -- for update() one only needs - to list the fields that are actually changed. - </para> - <para>Unless implementing a client driver, one needn't - concern oneself with the complications of the binary - protocol. <olink targetptr="connectors">Language-specific - drivers</olink> provide a friendly way to store domain - language data structures in Tarantool. - A complete description of the binary protocol - is maintained in annotated Backus-Naur - form in the source tree: please see - <link xlink:href="http://tarantool.org/doc/box-protocol.html"><filename>doc/box-protocol.html</filename></link>. - </para> -</section> - -<section xml:id="administrative-console"> - <title>Administrative console</title> - <para> - The administrative console is simply an outlet of the Tarantool - Lua interpreter. You can connect to the administrative port - using any <command>telnet</command> client, or a tool like - <command>rlwrap</command>, if access to readline features is - desired. Additionally, <command>tarantool</command>, the - command line client, may distinguish between requests types - and direct them to the appropriate port. - The server response to an administrative command, even though - it is always in plain text, can be quite complex. - It is encoded using YAML markup to simplify automated parsing. - </para> - <para>To learn which functions are considered to be administrative, - type <emphasis role="lua">help()</emphasis> in the - administrative console. A reference description also follows - below:</para> - - <variablelist> - - <varlistentry> - <term xml:id="box.snapshot" xreflabel="box.snapshot()"> - <emphasis role="lua">box.snapshot()</emphasis> - </term> - <listitem><para> - Take a snapshot of all data and store it in - <filename><olink - targetptr="snap_dir"/>/<latest-lsn>.snap</filename>. - To take a snapshot, Tarantool first enters the delayed - garbage collection mode for all data. In this mode, - tuples which were allocated before the snapshot has - started are not freed until the snapshot has finished. - To preserve consistency of the primary key, used to - iterate over tuples, a copy-on-write technique is employed. - If the master process changes part of a primary key, - the corresponding process page is split, and the snapshot - process obtains an old copy of the page. Since a - snapshot is written sequentially, one can expect a very - high write performance (averaging to 80MB/second on modern - disks), which means an average database instance gets - saved in a matter of minutes. Note, that as long as there - are any changes to the parent index memory through concurrent - updates, there are going to be page splits, and therefore - one needs to have some extra free memory to run this - command. 10% of <olink targetptr="slab_alloc_arena"/> - is, on average, sufficient. This statement waits until a - snapshot is taken and returns operation result. For - example: -<programlisting>tarantool> <userinput>box.info.version</userinput> ---- -- 1.6.0-805-g4a7e71d -... -tarantool> <userinput>box.snapshot()</userinput> ---- -ok -... -tarantool> <userinput>box.snapshot()</userinput> ---- -fail: can't save snapshot, errno 17 (File exists) -... -</programlisting> - </para> - <para> - Taking a snapshot does not cause the server to start a new - write-ahead log. Once a snapshot is taken, old WALs can be - deleted as long as all replicas are up to date. But the - WAL which was current at the time <emphasis - role="lua">box.snapshot()</emphasis> started must be - kept for recovery, since it still contains log records - written after the start of <emphasis role="lua"> - box.snapshot()</emphasis>. - </para> - <para> - An alternative way to save a snapshot is to send the server - SIGUSR1 UNIX signal. While this approach could be handy, it - is not recommended for use in automation: a signal provides no - way to find out whether the snapshot was taken successfully - or not. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="box.info" xreflabel="box.info()"> - <emphasis role="lua">box.info()</emphasis> - </term> - <listitem><para> -<programlisting> -<prompt>tarantool></prompt> <userinput>box.info()</userinput> -- version: 1.6.0-805-g4a7e71d - status: primary - pid: 12315 - lsn: 15481913304 - snapshot_pid: 0 - recovery_last_update: 1306964594 - recovery_lag: 0 - uptime: 441524 - build: - flags: ' -fno-omit-frame-pointer -fno-stack-protector -fexceptions - -funwind-tables -msse2 -std=gnu99 -Wall -Wextra -Wno-sign-compare - -Wno-strict-aliasing -fopenmp -pthread' - target: Linux-x86_64-Debug - compiler: /usr/bin/cc /usr/bin/c++ - options: cmake . -DCMAKE_INSTALL_PREFIX=/usr/local -DENABLE_STATIC=OFF - -DENABLE_TRACE=ON -DENABLE_BACKTRACE=ON -DENABLE_CLIENT=true - logger_pid: 12316 - config: /usr/local/etc/tarantool.cfg -</programlisting> - </para> - <para> - <emphasis role="strong">recovery_lag</emphasis> holds the - difference (in seconds) between the current time on the - machine (wall clock time) and the time stamp of the last - applied record. In replication setup, this difference can - indicate the delay taking place before a change is - applied to a replica. - </para> - <para> - <emphasis role="strong">recovery_last_update</emphasis> is - the wall clock time of the last change recorded in the - write-ahead log. To convert it to human-readable time, - you can use <command>date -d@<replaceable>1306964594.980</replaceable></command>. - </para> - <para> - <emphasis role="strong">status</emphasis> is - either "primary" or "replica/<hostname>". - </para> - - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="box.stat" xreflabel="box.stat"> - <emphasis role="lua">box.stat()</emphasis> - </term> - <listitem><para> - Show the average number of requests per second, and the - total number of requests since startup, broken down by - request type. -<programlisting> -tarantool> <userinput>box.stat()</userinput> ---- -- DELETE: - total: 48902544 - rps: 147 - SELECT: - total: 388322317 - rps: 1246 - REPLACE: - total: 0 - rps: 0 - INSERT: - total: 48207694 - rps: 139 - AUTH: - total: 0 - rps: 0 - CALL: - total: 0 - rps: 0 - UPDATE: - total: 743350520 - rps: 1874 -... -</programlisting> - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="box.slab.info" xreflabel="box.slab.info()"> - <emphasis role="lua">box.slab()</emphasis> - </term> - <listitem> - <para> - Show the statistics of the slab allocator. The slab - allocator is the main allocator used to store tuples. - This can be used to monitor the total memory use and - memory fragmentation. For example: - </para> -<programlisting> -<prompt>tarantool></prompt> <userinput>box.slab.info()</userinput> ---- -- slabs: - 64: - items: 16 - bytes_used: 1024 - item_size: 64 - slabs: 1 - bytes_free: 4193200 - ... - 136: - items: 1 - bytes_used: 136 - item_size: 136 - slabs: 1 - bytes_free: 4194088 - ... - arena_size: 8388448 - arena_used: 1160 -</programlisting> - <para> - The display of slabs is broken down by the slab size -- - 64-byte, 136-byte, and so on. The example omits the slabs - which are empty. The example display is saying that: - there are 16 items stored - in the 64-byte slab (and 16*64=1024 so - bytes_used = 1024); there is 1 item - stored in the 136-byte slab (and - 136*1=136 so bytes_used = 136); the - arena_used value is the total of all the bytes_used - values (1024+136 = 1160); the - arena_size value is the arena_used value - plus the total of all the bytes_free values - (1160+4193200+4194088 = 8388448). The - arena_size and arena_used values are the amount of - the % of <olink targetptr="slab_alloc_arena"/> that is - already distributed to the slab allocator. - </para> - <para> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="coredump" xreflabel="coredump()"> - <emphasis role="lua">coredump()</emphasis> - </term> - <listitem><para> - Fork and dump a core. Since Tarantool stores all tuples - in memory, it can take some time. Mainly useful for - debugging. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="fiber.info" xreflabel="fiber.info"> - <emphasis role="lua">require('fiber').info()</emphasis> - </term> - <listitem><para> - Show all running fibers, with their stack. - Mainly useful for debugging. - </para></listitem> - </varlistentry> - - </variablelist> - -</section> - -<xi:include href="stored-procedures.xml" /> -<xi:include href="triggers.xml" /> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/limitations.xml b/doc/user/limitations.xml deleted file mode 100644 index b606909779057ae761849909e6227fe7fbe5f572..0000000000000000000000000000000000000000 --- a/doc/user/limitations.xml +++ /dev/null @@ -1,64 +0,0 @@ -<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="limitations"> - -<title>Limitations</title> - - -<variablelist> - - <varlistentry> - <term xml:id="limitations-index-field-count" xreflabel="limitations-index-field-count">Number of fields in an index</term> - <listitem><para>For BITSET indexes, the maximum is 1. - For TREE indexes, the theoretical maximum is about 4 billion (BOX_FIELD_MAX) - but the practical maximum is the number of fields in a tuple. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-index-count" xreflabel="limitations-index-count">Number of indexes in a space</term> - <listitem><para>10 (BOX_INDEX_MAX). - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-tuple-field-count" xreflabel="limitations-tuple-field-count">Number of fields in a tuple</term> - <listitem><para>There is no theoretical maximum. - The practical maximum is whatever is specified by the space's <code>field_count</code> member, - or the maximum tuple length. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-space-count" xreflabel="limitations-space-count">Number of spaces</term> - <listitem><para>255. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-connections-count" xreflabel="limitations-connections-count">Number of connections</term> - <listitem><para>The practical limit is the number of file descriptors that one can set with - the operating system. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-slab-alloc-arena-size" xreflabel="limitations-slab-alloc-arena-size">Space size</term> - <listitem><para>The total maximum size for all spaces is in effect set by slab_alloc_arena, - which in turn is limited by the total available memory. - </para></listitem> - </varlistentry> - - <varlistentry> - <term xml:id="limitations-update-count" xreflabel="limitations-updae-count">Update operations count</term> - <listitem><para>The maximum number of operations that can be in a single update is 4000 (BOX_UPDATE_OP_CNT_MAX). - </para></listitem> - </varlistentry> - -</variablelist> -</appendix> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/lua-tutorial.xml b/doc/user/lua-tutorial.xml deleted file mode 100644 index 0be320b948ddaad1369884d9573de8865b710dcc..0000000000000000000000000000000000000000 --- a/doc/user/lua-tutorial.xml +++ /dev/null @@ -1,645 +0,0 @@ -<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="lua-tutorial"> - -<title>Lua tutorial</title> - -<section xml:id="lua-tutorial-insert"> -<title>Insert one million tuples with a Lua stored procedure</title> - -<para> -This is an exercise assignment: <quote>Insert one million tuples. -Each tuple should have a constantly-increasing numeric primary-key field -and a random alphabetic 10-character string field.</quote> -</para> - -<para> -The purpose of the exercise is to show what Lua functions -look like inside Tarantool. It will be necessary to employ -the Lua math library, the Lua string library, the Tarantool -box library, the Tarantool box.tuple library, loops, and concatenations. It should be easy -to follow even for a person who has not used either Lua -or Tarantool before. The only requirement is a knowledge -of how other programming languages work and a memory of -the first two chapters of this manual. But for better understanding, -follow the comments and the links, which point to the Lua -manual or to elsewhere in this Tarantool manual. -To further enhance learning, type the statements -in with the tarantool client while reading along. -</para> - -<para> -<bridgehead renderas="sect4">Configure</bridgehead> -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, -and a running tarantool server which also serves as a client. -</para> - -<para> -<bridgehead renderas="sect4">Delimiter</bridgehead> -We'll be making functions which go over one line. We don't want the client to send to the server after every line. -So we <link linkend="utility-tarantool-delim">declare a delimiter</link>. -This means <quote>Do not send to the server until you see an exclamation mark.</quote> - -<programlisting> -tarantool> <userinput>console = require('console'); console.delimiter('!')</userinput> -</programlisting> -From now on it will be possible to use multiple-line statements, -but it will be necessary to end all statements with exclamation marks. -</para> - -<para> -<bridgehead renderas="sect4">Create a function that returns a string</bridgehead> - -We will start by making a function that returns a fixed string, <quote>Hello world</quote>. -<programlisting> -function string_function() - return "hello world" - end! -</programlisting> -The word "function" is a Lua keyword -- we're about to go into Lua. -The function name is string_function. -The function has one executable statement, <code>return "hello world"</code>. -The string "hello world" is enclosed in double quotes here, -although Lua doesn't care -- one could use single quotes instead. -The word "end" means <quote>this is the end of the Lua function declaration.</quote> -The word "end" is followed by "!" because "!" happens to be the delimiter that we chose in the previous step. - -To confirm that the function works, we can say -<programlisting> -string_function()! -</programlisting> -Sending <replaceable>function-name</replaceable>() means <quote>invoke the Lua function.</quote> -The effect is that the string which the function returns will end up on the screen. -</para> - -<para> -For more about Lua strings see Lua manual chapter 2.4 "Strings" -<productname xlink:href="http://www.lua.org/pil/2.4.html">http://www.lua.org/pil/2.4.html</productname>. - -For more about functions see Lua manual chapter 5 "Functions" -<productname xlink:href="http://www.lua.org/pil/5.html">http://www.lua.org/pil/5.html</productname>. -</para> - -<para> -The screen now looks like this: -<programlisting> -tarantool> <userinput>function string_function()</userinput> - -> <userinput>return "hello world"</userinput> - -> <userinput>end!</userinput> ---- -... -tarantool> <userinput>string_function()!</userinput> ---- -- hello world -... -tarantool> -</programlisting> -</para> - - <para> -<bridgehead renderas="sect4">Create a function that calls another function and sets a variable</bridgehead> - -Now that string_function exists, we can invoke it from another function. -<programlisting> -function main_function() - local string_value - string_value = string_function() - return string_value - end! -</programlisting> -We begin by declaring a variable "string_value". -The word "local" means that string_value appears only in main_function. -If we didn't use "local" then string_value would be visible everywhere --- even by other users using other clients connected to this server! -Sometimes that's a very desirable feature for inter-client communication, but not this time. -</para> - -<para> -Then we assign a value to string_value, namely, the result of string_function(). -Soon we will invoke main_function() to check that it got the value. -</para> - -<para> -For more about Lua variables see Lua manual chapter 4.2 "Local Variables and Blocks" -<productname xlink:href="http://www.lua.org/pil/4.2.html">http://www.lua.org/pil/4.2.html</productname>. -</para> - -<para> -The screen now looks like this: -<programlisting> -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> ---- -... -tarantool> <userinput>main_function()!</userinput> ---- -- hello world -... -tarantool> -</programlisting> -</para> - -<para> -<bridgehead renderas="sect4">Modify the function so it returns a one-letter random string</bridgehead> - -Now that it's a bit clearer how to make a variable, we can change string_function() -so that, instead of returning a fixed literal 'Hello world", it returns a random letter between 'A' and 'Z'. -<programlisting> -function string_function() - local random_number - local random_string - random_number = math.random(65, 90) - random_string = string.char(random_number) - return random_string - end! -</programlisting> -It is not necessary to destroy the old string_function() contents, they're simply overwritten. -The first assignment invokes a random-number function in Lua's math library; the parameters mean <quote>the number must be an integer between 65 and 90.</quote> -The second assignment invokes an integer-to-character function in Lua's string library; the parameter is the code point of the character. -Luckily the ASCII value of 'A' is 65 and the ASCII value of 'Z' is 90 so the result will always be a letter between A and Z. -</para> - -<para> -For more about Lua math-library functions see Lua users "Math Library Tutorial" -<productname xlink:href="http://lua-users.org/wiki/MathLibraryTutorial">http://lua-users.org/wiki/MathLibraryTutorial</productname>. -For more about Lua string-library functions see Lua users "String Library Tutorial" -<productname xlink:href="http://lua-users.org/wiki/StringLibraryTutorial">http://lua-users.org/wiki/StringLibraryTutorial</productname>. -</para> - -<para> -Once again the string_function() can be invoked from main_function() which can be invoked with -</para> -<para> -main_function()! -</para> - -<para> -The screen now looks like this: -<programlisting> -tarantool> <userinput>function string_function()</userinput> - -> <userinput>local random_number</userinput> - -> <userinput>local random_string</userinput> - -> <userinput>random_number = math.random(65, 90)</userinput> - -> <userinput>random_string = string.char(random_number)</userinput> - -> <userinput>return random_string</userinput> - -> <userinput>end!</userinput> ---- -... -tarantool> <userinput>main_function()!</userinput> ---- -- C -... -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. -</para> - -<para> -<bridgehead renderas="sect4">Modify the function so it returns a ten-letter random string</bridgehead> -Now that it's clear how to produce one-letter random strings, we can reach our goal -of producing a ten-letter string by concatenating ten one-letter strings, in a loop. -<programlisting> -function string_function() - local random_number - local random_string - random_string = "" - for x = 1,10,1 do - random_number = math.random(65, 90) - random_string = random_string .. string.char(random_number) - end - return random_string - end! -</programlisting> -The words "for x = 1,10,1" mean <quote>start with x equals 1, loop until x equals 10, increment x by 1 for each iteration.</quote> -The symbol ".." means "concatenate", that is, add the string on the right of the ".." sign to the string on the left of the ".." sign. -Since we start by saying that random_string is "" (a blank string), the end result is that random_string has 10 random letters. - -Once again the string_function() can be invoked from main_function() which can be invoked with -</para> -<para> -main_function()! -</para> - -<para> -For more about Lua loops see Lua manual chapter 4.3.4 "Numeric for" -<productname xlink:href="http://www.lua.org/pil/4.3.4.html">http://www.lua.org/pil/4.3.4.html</productname>. -</para> - -<para> -The screen now looks like this: -<programlisting> -tarantool> <userinput>function string_function()</userinput> - -> <userinput>local random_number</userinput> - -> <userinput>local random_string</userinput> - -> <userinput>random_string = ""</userinput> - -> <userinput>for x = 1,10,1 do</userinput> - -> <userinput>random_number = math.random(65, 90)</userinput> - -> <userinput>random_string = random_string .. string.char(random_number)</userinput> - -> <userinput>end</userinput> - -> <userinput>return random_string</userinput> - -> <userinput>end!</userinput> ---- -... -tarantool> <userinput>main_function()!</userinput> ---- -- 'ZUDJBHKEFM' -... -tarantool> -</programlisting> -</para> - -<para> -<bridgehead renderas="sect4">Make a tuple out of a number and a string</bridgehead> - -Now that it's clear how to make a 10-letter random string, it's possible to -make a tuple that contains a number and a 10-letter random string, by invoking -a function in Tarantool's library of Lua functions. -<programlisting> -function main_function() - local string_value - string_value = string_function() - t = box.tuple.new({1, string_value}) - return t - end! -</programlisting> -Once this is done, t will be the value of a new tuple which has two -fields. The first field is numeric: 1. The second field is a random string. - -Once again the string_function() can be invoked from main_function() which can be invoked with -</para> -<para> -main_function()! -</para> - -<para> -For more about Tarantool tuples see Tarantool manual section -<olink targetptr="sp-box-tuple">Package box.tuple</olink>. -</para> - -<para> -The screen now looks like this: -<programlisting> -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> - -> <userinput>return t</userinput> - -> <userinput>end!</userinput> ---- -... -tarantool> <userinput>main_function()!</userinput> ---- -- [1, 'PNPZPCOOKA'] -... -tarantool> -</programlisting> -</para> - -<para> -<bridgehead renderas="sect4">Modify main_function to insert a tuple into the database</bridgehead> - -Now that it's clear how to make a tuple that contains a number and a 10-letter random string, -the only trick remaining is putting that tuple into tester. Remember that tester is -the first space that was defined in the sandbox, so it's like a database table. -<programlisting> -function main_function() - local string_value - string_value = string_function() - t = box.tuple.new({1,string_value}) - box.space.tester:replace(t) - end! -</programlisting> -The new line here is box.space.tester:replace(t). The name contains 'tester' because the -insertion is going to be to tester. The second parameter is the tuple value. -To be perfectly correct we could have said box.space.tester:insert(t) here, rather than -box.space.tester: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, tester 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 -<code>main_function()!</code>. But main_function() won't tell the whole story, because it does not -return t, it only puts t into the database. To confirm that something got inserted, we'll -use a SELECT request. - -<programlisting> -main_function()! -box.space.tester:select{1}! -</programlisting> -</para> - -<para> -For more about Tarantool insert and replace calls, see Tarantool manual section -<olink targetptr="sp-box">Package box</olink>. -</para> - -<para> -The screen now looks like this: -<programlisting> -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> - -> <userinput>box.space.tester:replace(t)</userinput> - -> <userinput>end!</userinput> ---- -... -tarantool> <userinput>main_function()!</userinput> ---- -... -tarantool> <userinput>box.space.tester:select{1}!</userinput> ---- -- - [1, 'EUJYVEECIL'] -... -tarantool> -</programlisting> -</para> - -<para> -<bridgehead renderas="sect4">Modify main_function to insert a million tuples into the database</bridgehead> - -Now that it's clear how to insert one tuple into the database, -it's no big deal to figure out how to scale up: instead of -inserting with a literal value = 1 for the primary key, insert -with a variable value = between 1 and 1 million, in a loop. -Since we already saw how to loop, that's a simple thing. -The only extra wrinkle that we add here is a timing function. -<programlisting> -function main_function() - local string_value - start_time = os.clock() - for i = 1,1000000,1 do - string_value = string_function() - t = box.tuple.new({i,string_value}) - box.space.tester:replace(t) - end - end_time = os.clock() - end! -main_function()! -'insert done in ' .. end_time - start_time .. ' seconds'! -</programlisting> - -The Lua os.clock() function will return the number of seconds since the start. -Therefore, by getting start_time = number of seconds just before the inserting, -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 also work.) -</para> - -<para> -For more on Lua os.clock() see Lua manual chapter 22.1 "Date and Time" -<productname xlink:href="http://www.lua.org/pil/22.1.html">http://www.lua.org/pil/22.1.html</productname>. -For more on Lua print() see Lua manual chapter 5 "Functions" -<productname xlink:href="http://www.lua.org/pil/5.html">http://www.lua.org/pil/5.html</productname>. -</para> - -<para> -Since this is the grand finale, we will redo the final versions of all the necessary -requests: the console.delimiter('!') request, the request that created string_function(), -the request that created main_function(), and the request that invokes main_function(). - - -<programlisting> -#Skip the following statement if you have already said "console.delimiter('!')" -console = require('console'); console.delimiter('!') - -function string_function() - local random_number - local random_string - random_string = "" - for x = 1,10,1 do - random_number = math.random(65, 90) - random_string = random_string .. string.char(random_number) - end - return random_string - end! - -function main_function() - local string_value - start_time = os.clock() - for i = 1,1000000,1 do - string_value = string_function() - t = box.tuple.new({i,string_value}) - box.space.tester:replace(t) - end - end_time = os.clock() - end! -main_function()! -'insert done in ' .. end_time - start_time .. ' seconds'! -</programlisting> - -The screen now looks like this: - -<programlisting> -tarantool> <userinput>console = require('console'); console.delimiter('!')</userinput> -tarantool> <userinput>function string_function()</userinput> - -> <userinput>local random_number</userinput> - -> <userinput>local random_string</userinput> - -> <userinput>random_string = ""</userinput> - -> <userinput>for x = 1,10,1 do</userinput> - -> <userinput>random_number = math.random(65, 90)</userinput> - -> <userinput>random_string = random_string .. string.char(random_number)</userinput> - -> <userinput>end</userinput> - -> <userinput>return random_string</userinput> - -> <userinput>end!</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> - -> <userinput>string_value = string_function()</userinput> - -> <userinput>t = box.tuple.new({i,string_value})</userinput> - -> <userinput>box.space.tester:replace(t)</userinput> - -> <userinput>end</userinput> - -> <userinput>end_time = os.clock()</userinput> - -> <userinput>end!</userinput> ---- -... -tarantool> <userinput>main_function()!</userinput> ---- -... -tarantool> <userinput>'insert done in ' .. end_time - start_time .. ' seconds'!</userinput> ---- -- insert done in 60.62 seconds -... -tarantool> -</programlisting> -</para> - -<para> -What has been shown is that Lua functions are quite expressive -(in fact one can do more with Tarantool's Lua stored procedures -than one can do with stored procedures in some SQL DBMSs), and -that it's straightforward to combine Lua-library functions and -Tarantool-library functions. -</para> - -<para> -What has also been shown is that inserting a million -tuples took 60 seconds. The host computer was a Toshiba -laptop with a 2.2-GHz Intel Core Duo CPU. -</para> - -</section> - -<section xml:id="lua-tutorial-sum"> -<title>Sum a JSON field for all tuples</title> - -<para> -This is an exercise assignment: <quote>Assume that inside every tuple there -is a string formatted as JSON. Inside that string there is a JSON numeric -field. For each tuple, find the numeric field's value and add it to a -'sum' variable. At end, return the 'sum' variable.</quote> -The purpose of the exercise is to get experience in one way -to read and process tuples. -</para> - -<programlisting language="lua"> -console = require('console'); console.delimiter('!') -function sum_json_field(field_name) - json = require('json') - local v, t, sum, field_value, is_valid_json, lua_table --[[1]] - sum = 0 --[[2]] - for v, t in box.space.tester:pairs() do --[[3]] - is_valid_json, lua_table = pcall(json.decode, t[2]) --[[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! -console.delimiter('')! -</programlisting> - -<para> -LINE 1: WHY "LOCAL". This line declares all the variables that will be used -in the function. Actually it's not necessary to declare all variables at the start, -and in a long function it would be better to declare variables just before using -them. In fact it's not even necessary to declare variables at all, but an -undeclared variable is "global". That's not desirable for any of the variables -that are declared in line 1, because all of them are for use only within the -function. -</para> - -<para> -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 -pairs() because it is simpler. -</para> - -<para> -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 4: WHY "PCALL". If we simply said "<code>lua_table = json.decode(t[2]))</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 -of error, so if there's a problem just set <code>is_valid_json = false</code> and we -will know what to do about it later. -</para> - -<para> -LINE 4: MEANING. The function is <olink targetptr="box.cjson">json.decode</olink> which means decode a JSON -string, and the parameter is <code>t[2]</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[1]: 444 -field[2]: '{"Hello": "world", "Quantity": 15}' -</programlisting>meaning that the tuple's first field, the primary key field, is a number -while the tuple's second field, the JSON string, is a string. Thus the -entire statement means "decode <code>t[2]</code> (the tuple's second field) as a JSON -string; if there's an error set <code>is_valid_json = false</code>; if there's no error -set <code>is_valid_json = true</code> and set <code>lua_table</code> = a Lua table which has the -decoded string". -</para> - -<para> -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 -'{"Hello": "world", "Quantity": 15}', there are two JSON fields: "Hello" -and "Quantity". If the whole function is invoked with <code>sum_json_field("Quantity")</code>, -then <code>field_value = lua_table[field_name]</code> is effectively the same as -<code>field_value = lua_table["Quantity"]</code> or even <code>field_value = lua_table.Quantity</code>. -Those are just three different ways of saying: for the Quantity field -in the Lua table, get the value and put it in variable <code>field_value</code>. -</para> - -<para> -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. -Anyone who knows that the database is in perfect shape can skip this kind of thing. -</para> - -<para> -And the function is complete. Time to test it. -Starting with an empty database, defined the same way as the -sandbox database that was introduced in -<olink -targetptr="getting-started-start-stop"><quote>Starting Tarantool and making your first database</quote></olink>, - -<programlisting> -box.space.tester:drop() -- if tester is left over from some previous test, destroy it -box.schema.space.create('tester') -box.space.tester:create_index('primary', {parts = {1, 'NUM'}}) -</programlisting> -then add some tuples where the first field is a number and the second field is a string. -</para> -<programlisting> -box.space.tester:insert{444, '{"Item": "widget", "Quantity": 15}'} -box.space.tester:insert{445, '{"Item": "widget", "Quantity": 7}'} -box.space.tester:insert{446, '{"Item": "golf club", "Quantity": "sunshine"}'} -box.space.tester:insert{447, '{"Item": "waffle iron", "Quantit": 3}'} -</programlisting> -<para> -Since this is a test, there are deliberate errors. The "golf club" and -the "waffle iron" do not have numeric Quantity fields, so must be ignored. -Therefore the real sum of the Quantity field in the JSON strings should be: -15 + 7 = 22. -</para> - -<para> -Invoke the function with <code>sum_json_field("Quantity")</code>. -<programlisting language="lua"> -<prompt>tarantool></prompt> <userinput>sum_json_field("Quantity")</userinput> ---- -- 22 -... -</programlisting> -</para> - -<para> -It works. We'll just leave, as exercises for future improvement, the possibility -that the "hard coding" assumptions could be removed, that there might have to be -an overflow check if some field values are huge, and that the function should -contain a "yield" instruction if the count of tuples is huge. -</para> - -</section> - -</appendix> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> - diff --git a/doc/user/olinkdb.xml b/doc/user/olinkdb.xml deleted file mode 100644 index affaca2bee9efeccb94b1efc99ee721576eaef4f..0000000000000000000000000000000000000000 --- a/doc/user/olinkdb.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<targetset> - <document targetdoc="tarantool-user-guide"> - <xi:include href="target.db" xmlns:xi="http://www.w3.org/2001/XInclude"/> - </document> -</targetset> diff --git a/doc/user/persistence-architecture.xml b/doc/user/persistence-architecture.xml deleted file mode 100644 index f5c7a71d3054e73fa1ec0103d331cbb06c1d6359..0000000000000000000000000000000000000000 --- a/doc/user/persistence-architecture.xml +++ /dev/null @@ -1,133 +0,0 @@ -<!DOCTYPE section [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<section xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="data-persistence"> -<title>Data persistence</title> -<para> -To maintain data persistence, Tarantool writes each data change -request (INSERT, UPDATE, DELETE, REPLACE) into a write-ahead log (WAL) -file in the <olink targetptr="wal_dir"/> directory. -A new WAL file is created for every <olink -targetptr="rows_per_wal"/> records. Each data change request -gets assigned a continuously growing 64-bit log sequence number. -The name of the WAL file is based on the log sequence -number of the first record in the file, plus an extension <filename>.xlog</filename>. -</para> - -<para>Apart from a log sequence number and the data change request -(its format is the same as in the binary protocol and is described -in <link -xlink:href="http://tarantool.org/doc/box-protocol.html"><filename>doc/box-protocol.html</filename></link>), -each WAL record contains a header, some metadata, and then the data formatted -according to <link xlink:href="https://github.com/msgpack/msgpack/blob/master/spec.md">msgpack rules</link>. -For example this is what the WAL file looks like after the first INSERT -request ("s:insert({1})") for the introductory sandbox exercise -<olink -targetptr="getting-started-start-stop"><quote>Starting Tarantool and making your first database</quote></olink>. -On the left are the hexadecimal bytes that one would see with -<programlisting><prompt>$ </prompt><userinput>hexdump 00000000000000000001.xlog</userinput></programlisting> -and on the right are comments. -<programlisting> -Hex dump of WAL file Comment --------------------- ------- -58 4c 4f 47 0a File header: "XLOG\n" -30 2e 31 32 0a 0a File header: "0.12\n\n" = version -... (not shown = inserted tuples for LSN and system spaces) -d5 ba 0b ab Magic row marker always = 0xab0bbad5 if version 0.12 -19 00 Length, not including length of header, = 25 bytes -ce 16 a4 38 6f Record header: previous crc32, current crc32, -a7 cc 73 7f 00 00 66 39 -84 msgpack code meaning "Map of 4 elements" follows -00 02 02 01 the 4 elements, including 0x02 which is IPROTO_INSERT -03 04 04 additional information -cb 41 d4 e2 2f 62 fd d5 d4 msgpack code meaning "Double" follows, for next 8 bytes -82 msgpack code meaning "map of 2 elements" follows -10 IPROTO_SPACE_ID which is #defined as 16 (hex 10) -cd msgpack code meaning 2-digit number follows -02 00 the id of "tester" which is 513, it's biggest byte first -21 Flags = IPROTO_TUPLE which is #defined as hex 21 -91 msgpack code meaning "1-element fixed array" follows -01 Tuple: field[1] value = 1 -</programlisting> -</para> - -<para> -Tarantool processes requests atomically: a change is either -accepted and recorded in the WAL, or discarded completely. -Let's clarify how this happens, using the REPLACE request as an -example: -<orderedlist> - <listitem><para> - The server attempts to locate the original tuple by - primary key. If found, a reference to the tuple is retained - for later use. - </para></listitem> - <listitem><para> - The new tuple is then <emphasis>validated</emphasis>. If - for example it does not contain an indexed field, - or it has an indexed field whose type does not - match the type according to the index definition, - the change is aborted. - </para></listitem> - <listitem><para> - The new tuple replaces the old tuple in all - existing indexes. - </para></listitem> - <listitem><para> - A message is sent to WAL writer running in a - separate thread, requesting that the change be recorded in the WAL. - The server switches to work on the next request until the write - is acknowledged. - </para></listitem> - <listitem><para> - On success, a confirmation is sent to the client. Upon - failure, a rollback procedure is begun. During the rollback - procedure, the transaction processor rolls back all changes to - the database which occurred after the first failed change, from - latest to oldest, up to the first failed change. All rolled back - requests are aborted with <olink targetptr="ER_WAL_IO"/> - error. No new change is applied while rollback is in progress. - When the rollback procedure is finished, the server restarts - the processing pipeline. - </para></listitem> -</orderedlist> -</para> - -<para> -One advantage of the described algorithm is that complete request -pipelining is achieved, even for requests on the same value of the -primary key. As a result, database performance doesn't degrade -even if all requests touch upon the same key in the same space. -</para> - -<para> -The transaction processor thread communicates with the WAL writer thread -using asynchronous (yet reliable) messaging; the transaction -processor thread, not being blocked on WAL tasks, continues to -handle requests quickly even at high volumes of disk I/O. A -response to a request is sent as soon as it is ready, even if -there were earlier incomplete requests on the same connection. In -particular, SELECT performance, even for SELECTs running on a -connection packed with UPDATEs and DELETEs, remains unaffected by -disk load. -</para> - -<para> -The WAL writer employs a number of durability modes, as defined -in configuration variable <olink targetptr="wal_mode"/>. It is -possible to turn the write-ahead log completely off, by setting -<olink targetptr="wal_mode"/> to <emphasis>none</emphasis>. -Even without the write-ahead log it's still possible to take a -persistent copy of the entire data set with the -<olink targetptr="box.snapshot"/> statement. -</para> - - -</section> -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/plugins.xml b/doc/user/plugins.xml deleted file mode 100644 index 6227a72493afc460e1cd3adfb28d071587243109..0000000000000000000000000000000000000000 --- a/doc/user/plugins.xml +++ /dev/null @@ -1,317 +0,0 @@ -<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="plugins"> - -<title>Plugins</title> - -<para> -A plugin is an optional library which enhances Tarantool functionality. -</para> - -<para> -The details of creating one's own plugin are described on -<productname xlink:href="https://github.com/tarantool/tarantool/wiki/Plugin-API">the Tarantool Plugin API wiki page</productname>. -</para> - -<para> -The discussion here in the user guide is about incorporating and using -two plugins that have already been created: the "SQL DBMS plugins" for -MySQL and PostgreSQL. -</para> - -<para xml:id="plugin-sql-dbms-plugins"> -<bridgehead renderas="sect4">SQL DBMS Plugins</bridgehead> -To call another DBMS from Tarantool, the essential requirements are: -another DBMS, and Tarantool. -</para> - -<para> -It will be necessary to build Tarantool from source, -as described in -<link xlink:href="http://tarantool.org/doc/dev_guide/building_from_source.html"><quote>Building from source</quote></link> -</para> - -<para> -The Tarantool plugins allow for connecting to an SQL server -and executing SQL statements the same way that a MySQL or PostgreSQL client does. -The SQL statements are visible as Lua methods. Thus Tarantool can -serve as a "MySQL Lua Connector" or "PostgreSQL Lua Connector", which would be useful even if -that was all Tarantool could do. But of course Tarantool is also -a DBMS, so the plugin also is useful for any operations, such as -database copying and accelerating, which work best when the application -can work on both SQL and Tarantool inside the same Lua routine. -</para> - -<para> -The connection method is -<code>box.net.sql.connect('mysql'|'pg', <replaceable>host</replaceable>, <replaceable>port</replaceable>, <replaceable>user</replaceable>, <replaceable>password</replaceable>, <replaceable>database</replaceable>)</code>. -The methods for select/insert/etc. are the same as the ones in <link linkend="sp-net-box">the net.box package</link>. -</para> - -<para xml:id="plugin-mysql-example"> -<bridgehead renderas="sect4">MySQL Example</bridgehead> -This example assumes that MySQL 5.5 or MySQL 5.6 has been installed -(recent MariaDB versions should also work). -</para> - -<para> -The example was run on a Linux machine where the base directory -had a copy of the Tarantool source on ~/tarantool, and -a copy of MySQL on ~/mysql-5.5. The mysqld server is already running -on the local host 127.0.0.1. -</para> - -<programlisting> -# Check that the include subdirectory exists by looking for .../include/mysql.h. -# (If this fails, there's a chance that it's in .../include/mysql/mysql.h instead.) -<prompt>$ </prompt><userinput>[ -f ~/mysql-5.5/include/mysql.h ] && echo "OK" || echo "Error"</userinput> -OK - -# Check that the library subdirectory exists and has the necessary .so file. -<prompt>$ </prompt><userinput>[ -f ~/mysql-5.5/lib/libmysqlclient.so ] && echo "OK" || echo "Error"</userinput> -OK - -# Check that the mysql client can connect using some factory defaults: -# 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) -... -Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. - -<prompt>mysql></prompt> - -# Insert a row in database test, and quit. -<prompt>mysql></prompt> <userinput>CREATE TABLE IF NOT EXISTS test (s1 INT, s2 VARCHAR(50));</userinput> -Query OK, 0 rows affected (0.13 sec) -<prompt>mysql></prompt> <userinput>INSERT INTO test.test VALUES (1,'MySQL row');</userinput> -Query OK, 1 row affected (0.02 sec) -<prompt>mysql></prompt> <userinput>QUIT</userinput> -Bye - -# Build the Tarantool server. Make certain that "cmake" gets the right -# paths for the MySQL include directory and the MySQL libmysqlclient -# library which were checked earlier. -<prompt>$ </prompt><userinput>cd ~/tarantool</userinput> -<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</userinput> -... --- Found MySQL includes: ~/mysql-5.5/include/mysql.h --- Found MySQL library: ~/mysql-5.5/lib/libmysqlclient.so -... --- Configuring done --- Generating done --- Build files have been written to: ~/tarantool -<prompt>$ </prompt><userinput>make</userinput> -... -Scanning dependencies of target mysql -[ 79%] Building CXX object src/module/mysql/CMakeFiles/mysql.dir/mysql.cc.o -Linking CXX shared library libmysql.so -[ 79%] Built target mysql -... -[100%] Built target man -<prompt>$ </prompt> - -# The MySQL module should now be in ./src/module/mysql/mysql.so. -# If a "make install" had been done, then mysql.so would be in a -# different place, for example -# /usr/local/lib/x86_64-linux-gnu/tarantool/box/net/mysql.so. -# In that case there should be additional cmake options such as -# -DCMAKE_INSTALL_LIBDIR and -DCMAKE_INSTALL_PREFIX. -# For this example we assume that "make install" is not done. - -# 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/mysql/mysql.so ./box/net/mysql.so</userinput> - -# Start the Tarantool server. Do not use a Lua initialization file. - -<prompt>$ </prompt><userinput>~/tarantool/src/tarantool</userinput> -~/tarantool/src/tarantool: version 1.6.3-439-g7e1011b -type 'help' for interactive help -<prompt>tarantool> </prompt> <userinput>box.cfg{}</userinput> -... -# 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 both 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 earlier in the Tarantool user manual. -<prompt>tarantool> </prompt><userinput>console = require('console'); console.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', '', '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> 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> end!</userinput> ---- -... -<prompt>tarantool> </prompt><userinput>console.delimiter('')!</userinput> -<prompt>tarantool> </prompt> - -# Execute the Lua function. -<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. -</programlisting> - -<para xml:id="plugin-postgresql-example"> -<bridgehead renderas="sect4">PostgreSQL Example</bridgehead> -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> -If that works, then cmake will find the necessary files without requiring any special user input. -However, because not all platforms are alike, for this example the assumption is -that the user must check that the appropriate PostgreSQL files are present and -must explicitly state where they are when building Tarantool from source. -</para> - -<para> -The example was run on a Linux machine where the base directory -had a copy of the Tarantool source on ~/tarantool, and -a copy of PostgreSQL on /usr. The postgres server is already running -on the local host 127.0.0.1. -</para> - -<programlisting> -# Check that the include subdirectory exists -# by looking for /usr/include/postgresql/libpq-fe-h. -<prompt>$ </prompt><userinput>[ -f /usr/include/postgresql/libpq-fe.h ] && echo "OK" || echo "Error"</userinput> -OK - -# Check that the library subdirectory exists and has the necessary .so file. -<prompt>$ </prompt><userinput>[ -f /usr/lib/libpq.so ] && echo "OK" || echo "Error"</userinput> -OK - -# Check that the psql client can connect using some factory defaults: -# 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> -Password for user postgres: -psql (9.3.0, server 9.3.2) -SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) -Type "help" for help. - -<prompt>postgres=#</prompt> <userinput>CREATE TABLE test (s1 INT, s2 VARCHAR(50));</userinput> -CREATE TABLE -<prompt>postgres=#</prompt> <userinput>INSERT INTO test VALUES (1,'PostgreSQL row');</userinput> -INSERT 0 1 -<prompt>postgres=#</prompt> <userinput>\q</userinput> -<prompt>$ </prompt> - -# Build the Tarantool server. Make certain that "cmake" gets the right -# paths for the PostgreSQL include directory and the PostgreSQL libpq -# library which were checked earlier. -<prompt>$ </prompt><userinput>cd ~/tarantool</userinput> -<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</userinput> -... --- 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> -... -[ 79%] Building CXX object src/plugin/pg/CMakeFiles/pg.dir/pg.cc.o -Linking CXX shared library libpg.so -[ 79%] Built target pg -... -[100%] Built target man -<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. Do not use a Lua initialization file. - -<prompt>$ </prompt><userinput>~/tarantool/src/tarantool</userinput> -~/tarantool/src/tarantool: version 1.6.3-439-g7e1011b -type 'help' for interactive help -<prompt>tarantool> </prompt> <userinput>box.cfg{}</userinput> - -# 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>tarantool> </prompt><userinput>console = require('console'); console.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> 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> end!</userinput> ---- -... -<prompt>tarantool> </prompt><userinput>console.delimiter('')!</userinput> -<prompt>tarantool> </prompt> - -# Execute the Lua function. -<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. -# And now it's been selected with the Tarantool client. -</programlisting> - - -</appendix> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> - - - diff --git a/doc/user/preface.xml b/doc/user/preface.xml deleted file mode 100644 index 23e640af369f5f178ac21f19be661b53f2e43842..0000000000000000000000000000000000000000 --- a/doc/user/preface.xml +++ /dev/null @@ -1,222 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="preface"> -<title>Preface</title> -<section xml:id="tarantool-overview"> - <title>Tarantool: an overview</title> - <para> - <productname>Tarantool</productname> is a Lua application server integrated with a database management system. - It has a "fiber" model which means that many applications can run simultaneously on a single - thread, while the Tarantool server can run multiple threads for input-output and background maintenance. - It integrates the LuaJIT -- "Just In Time" -- Lua compiler, Lua libraries for most common - applications, and the Tarantool Database Server which is an established - NoSQL DBMS. Thus it serves all the purposes that have made node.js and Twisted popular in - other environments, with the additional twist that it has a data persistence level. - </para> - - <para> - The code is free. The open-source license is <citetitle - xlink:href="http://www.gnu.org/licenses/license-list.html#ModifiedBSD">BSD - license</citetitle>. The supported platforms are GNU/Linux, Mac OS - and FreeBSD. - </para> - - <para> - Tarantool's creator and biggest user is <citetitle xlink:href="https://en.wikipedia.org/wiki/Mail.ru">Mail.Ru</citetitle>, - the largest internet company in Russia, with 30 million users, 25 million emails per day, - and a web site whose Alexa global rank is in the <link xlink:href="http://www.alexa.com/siteinfo/mail.ru">top 40</link> worldwide. - Tarantool services Mail.Ru's hottest data, such as the session data of online users, - the properties of online applications, the caches of the underlying data, - the distribution and sharding algorithms, and much more. - Outside Mail.Ru the software is used by a growing - number of projects in online gaming, digital marketing, and social - media industries. While product development is sponsored by Mail.Ru, the - roadmap, the bugs database and the development process are fully - open. The software incorporates patches from dozens of - community contributors. The Tarantool community writes and maintains - most of the drivers for programming languages. - The greater Lua community has hundreds of useful packages - which can become Tarantool extensions. - </para> - - <para> - Users can create, modify and drop <emphasis - role="strong">Lua functions</emphasis> at runtime. - Or they can define <emphasis role="strong">Lua programs</emphasis> - that are loaded during startup for triggers, background tasks, - and interacting with networked peers. - Unlike popular application development frameworks based on - a "reactor" pattern, networking in server-side Lua is - sequential, yet very efficient, as it is built on top of the - <emphasis role="strong">cooperative multitasking</emphasis> - environment that Tarantool itself uses. - A key feature is that the functions - can access and modify databases atomically. - Thus some developers look at it as a DBMS with a popular stored procedure language, - while others look at it as a replacement for multiple components - of multi-tier Web application architectures. - Performance is a few thousand transactions per second - on a laptop, scalable upwards or outwards to server farms. - </para> - - <para> - <emphasis role="strong">Tarantool is lock-free</emphasis>. - Instead of the operating system's concurrency primitives, such - as mutexes, Tarantool uses cooperative - multitasking to handle thousands of connections simultaneously. - There is a fixed number of independent execution threads. - The threads do not share state. Instead they - exchange data using low-overhead message queues. While this - approach limits the number of cores that the server will use, - it removes competition for the memory bus and ensures peak - scalability of memory access and network throughput. - CPU utilization of a typical highly-loaded - Tarantool server is under 10%. - </para> - - <para> - Although Tarantool can run without it, the database management component is a - strong distinguishing feature. So here is a closer look at "The Box", - or DBMS server. - </para> - - <para> - Ordinarily the server <emphasis role="strong">keeps all the data in - random-access memory</emphasis>, and therefore has very low read - latency. - The server <emphasis role="strong">keeps persistent copies of - the data in non-volatile storage</emphasis>, such as disk, - when users request "snapshots". The server <emphasis role="strong"> - maintains a write-ahead log (WAL)</emphasis> to ensure - consistency and crash safety of the persistent copies. - The server <emphasis role="strong">performs inserts and updates atomically</emphasis> -- - changes are not considered complete until the WAL is written. - The logging subsystem supports group commit. - </para> - - <para> - When the rate of data changes is high, the write-ahead log file - (or files) can grow quickly. This uses up disk space, and - increases the time necessary to restart the server (because - the server must start with the last snapshot, and then replay - the transactions that are in the log). The solution is to - make snapshots frequently. Therefore the server ensures that - <emphasis role="strong">snapshots are quick, resource-savvy, and non-blocking - </emphasis>. To accomplish this, the server uses delayed garbage - collection for data pages and uses a copy-on-write technique for - index pages. This ensures that the snapshot process has a - consistent read view. - </para> - - <para> - Unlike most NoSQL DBMSs, Tarantool supports - <emphasis role="strong">secondary index keys</emphasis> as well as primary keys, and - <emphasis role="strong">multi-part index keys</emphasis>. - The possible index types are - HASH, TREE, BITSET, and RTREE. - </para> - - <para> - Tarantool supports - <emphasis role="strong">asynchronous replication</emphasis>, - locally or to remote hosts. - In this latest version the replication architecture can be - <emphasis role="strong">master-master</emphasis>, that is, - many nodes may both handle the loads and receive what others - have handled, for the same data sets. - </para> - - -</section> -<section xml:id="manual-conventions"> - <title>Conventions</title> - <para> - This manual is written in <citetitle - xlink:href="http://www.docbook.org/tdg5/en/html/docbook.html">DocBook - 5</citetitle> XML markup language and is using the standard <citetitle - xlink:href="http://docbook.sourceforge.net/release/xsl/current/doc/">DocBook - XSL</citetitle> formatting conventions:</para> - <para> - UNIX shell command input is prefixed with '$ ' and is in - a fixed-width font: - <programlisting><prompt>$ </prompt>tarantool <option>--help</option></programlisting> - </para> - <para> - File names are also in a fixed-width font: - <programlisting><filename>/path/to/var/dir</filename></programlisting> - </para> - <para> - Text that represents user input is in boldface: - <programlisting><prompt>$ </prompt><userinput>your input here</userinput></programlisting> - </para> - <para> - Within user input, replaceable items are in italics: - <programlisting><prompt>$ </prompt><userinput>tarantool <replaceable>--option</replaceable></userinput></programlisting> - </para> -</section> - -<section xml:id="how-to-read"> - <title>How to read the documentation</title> - <para> - To get started, one can either download the whole package as described in - the first part of Chapter 2 "Getting started", or one can initially skip - the download and connect to the online Tarantool server running on the web at - <link xlink:href="http://try.tarantool.org">http://try.tarantool.org</link>. - Either way, the first tryout can be a matter of following the example - in the second part of chapter 2: <link linkend="getting-started-start-stop">"Starting Tarantool and making your first - database"</link>. - </para> - <para> - Chapter 3 <link linkend="databases">"Databases"</link> is about the Tarantool NoSQL DBMS. - If the only intent is to use Tarantool as a Lua application server, - most of the material in this chapter and in the following chapter - (Chapter 4 <link linkend="replication">"Replication"</link>) will not be necessary. Once again, the - detailed instructions about each package can be regarded as reference - material. - </para> - <para> - Chapter 5 <link linkend="server-administration">"Server administration"</link> and Chapter 8 <link linkend="configuration-reference">"Configuration reference"</link> - are primarily for administrators; however, every user should know - something about how the server is configured so the section about - <code>box.cfg</code> is not skippable. Chapter 9 <link linkend="connectors">"Connectors"</link> is strictly for - users who are connecting from a different language such as C or Perl or - Python -- other users will find no immediate need for this chapter. - </para> - <para> - The two long tutorials in Appendix C -- <link linkend="lua-tutorial-insert">"Insert one million tuples with a Lua - stored procedure"</link> and <link linkend="lua-tutorial-sum">"Sum a JSON field for all tuples"</link> -- start - slowly and contain commentary that is especially aimed at users - who may not consider themselves experts at either Lua or NoSQL - database management. - </para> - <para> - Finally, Appendix D <link linkend="plugins">"Plugins"</link> has examples that will be essential - for those users who want to connect the Tarantool server to another - DBMS: MySQL or PostgreSQL. - </para> - <para> - For experienced users, there is also a developer's guide - and an extensive set of comments in the source code. - </para> -</section> - -<section xml:id="reporting-bugs"> - <title>Reporting bugs</title> - <para> - Please report bugs in Tarantool at <link - xlink:href="http://github.com/tarantool/tarantool/issues"/>. You can - contact developers directly on the - <link xlink:href="irc://irc.freenode.net#tarantool">#tarantool</link> - IRC channel on freenode, or via a mailing list, - <link xlink:href="https://googlegroups.com/group/tarantool">Tarantool Google group</link>. - </para> -</section> - -</chapter> -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en ---> diff --git a/doc/user/proctitle.xml b/doc/user/proctitle.xml deleted file mode 100644 index a3e5cd19864d714ccefc2cb5dc2dc6c1ac223817..0000000000000000000000000000000000000000 --- a/doc/user/proctitle.xml +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="proctitle"> - -<title>Server process titles</title> - -<para> - Linux and FreeBSD operating systems allow a running process to - modify its title, which otherwise contains the program name. - Tarantool uses this feature to help meet the needs of system - administration, such as figuring out what services are running - on a host, their status, and so on. -</para> -<para> - A Tarantool server process title follows the following naming scheme: - <command><replaceable>program_name</replaceable>: <replaceable>role</replaceable>[@<olink targetptr="custom_proc_title"/>]</command> -</para> -<para> - <emphasis role="strong">program_name</emphasis> is typically - <command>tarantool</command>. The role can be one of the - following: - <itemizedlist> - - <listitem><para> - <emphasis role="strong">running</emphasis> -- ordinary node "ready to accept requests", - </para></listitem> - <listitem><para> - <emphasis role="strong">loading</emphasis> -- ordinary node recovering from old snap and wal files, - </para></listitem> - <listitem><para> - <emphasis role="strong">orphan</emphasis> -- not in a cluster, - </para></listitem> - <listitem><para> - <emphasis role="strong">hot_standby</emphasis> -- see section <olink targetptr="local_hot_standby"/>, - </para></listitem> - <listitem><para> - <emphasis role="strong">dumper + process-id</emphasis> -- saving files before exiting, - </para></listitem> - <listitem><para> - <emphasis role="strong">spawner</emphasis> -- controls other processes, - </para></listitem> - <listitem><para> - <emphasis role="strong">replica + URI/status</emphasis> -- replication node accepting connections on <olink targetptr="replication_port"/>, - </para></listitem> - <listitem><para> - <emphasis role="strong">relay + sockaddr</emphasis> -- serves a single replication connection, - </para></listitem> - </itemizedlist> -</para> -<para> -For example:<programlisting><prompt>$</prompt> <userinput>ps -A -f | grep tarantool</userinput> -1000 17701 2778 0 08:27 pts/0 00:00:00 tarantool: running -1000 17704 17701 0 08:27 pts/0 00:00:00 tarantool: spawner</programlisting> -</para> -</appendix> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> - diff --git a/doc/user/replication.xml b/doc/user/replication.xml deleted file mode 100644 index c03ba8eb04ed7e74f50ca94f11a5aac6bc149b5a..0000000000000000000000000000000000000000 --- a/doc/user/replication.xml +++ /dev/null @@ -1,804 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="replication"> - -<title>Replication</title> - -<para> -Replication allows multiple Tarantool servers to work on -copies of the same databases. The databases are kept in -synch because each server can communicate its changes to -all the other servers. Servers which share the same databases -are a "cluster". Each server in a cluster also has a numeric -identifier which is unique within the cluster, known as the -"server id". -</para> - -<blockquote><para> - To set up replication, it's necessary to set up the master - servers which make the original data-change requests, - set up the replica servers which copy data-change requests - from masters, and establish procedures for recovery from - a degraded state. -</para></blockquote> - -<section xml:id="replication-architecture"> - <title>Replication architecture</title> - <para> - A replica gets all updates from the master by continuously - fetching and applying its write-ahead log (WAL). - Each record in the WAL represents a single Tarantool - data-change request such as INSERT or UPDATE or DELETE, and is assigned - a monotonically growing log sequence number (LSN). - In essence, Tarantool replication is row-based: - each data change command is fully deterministic and operates - on a single tuple. - </para> - <para> - A stored program invocation - <!-- , unless requested explicitly, --> - is not written to the write-ahead log. Instead, log events - for actual data-change requests, performed by the Lua code, - are written to the log. This ensures that possible - non-determinism of Lua does not cause replication - to go out of sync. - </para> -<!-- - <para> - It is still sometimes necessary to replicate stored program - CALLs, rather than their effects: for example, when the - procedure is fully deterministic and CALL representation in - the WAL is known to be significantly more compact. Another - example would be when a procedure is written to do one thing - on the master, and another on a replica. BOX_RPL_STMT - flag of the binary protocol can be used - to replicate CALLs as statements. - </para> ---> - -</section> - -<section xml:id="setting-up-the-master"> - <title>Setting up the master</title> - <para> - To prepare the master for connections from the replica, it's only - necessary to include "listen" in the initial <code>box.cfg</code> - request, for example <code>box.cfg{listen=3301}</code>. - A master with enabled "listen" <link linkend="URI">URI</link> can accept connections - from as many replicas as necessary on that URI. Each replica - has its own replication state. - </para> -</section> -<section xml:id="settin-up-a-replica"> - <title>Setting up a replica</title> - <para> - A server requires a valid snapshot (.snap) file. - A snapshot file is created for a server the first time that - <code>box.cfg</code> occurs for it. - If this first <code>box.cfg</code> request occurs without - a "replication_source" clause, then the server is a master - and starts its own new cluster with a new unique UUID. - If this first <code>box.cfg</code> request occurs with - a "replication_source" clause, then the server is a replica - and its snapshot file, along with the cluster information, - is constructed from the write-ahead logs of the master. Therefore, - to start replication, specify <olink - targetptr="replication_source"/> in a <code>box.cfg</code> request. - When a replica contacts a master for the first time, it becomes part of a cluster. - On subsequent occasions, it should always contact a master in the same cluster. - </para> - <para> - Once connected to the master, the replica requests all changes - that happened after the latest local LSN. It is therefore - necessary to keep WAL files on the master host as long as - there are replicas that haven't applied them yet. - A replica can be "re-seeded" by deleting all its files (the snapshot .snap file - and the WAL .xlog files), then starting replication again -- the replica will - then catch up with the master by retrieving all the master's tuples. - Again, this procedure works only if the master's WAL files are present. - </para> - <note><simpara> - Replication parameters are "dynamic", which allows the - replica to become a master and vice versa with the help of the - <olink targetptr="box.cfg">box.cfg</olink> statement. - </simpara></note> - <note><simpara> - The replica does not inherit the master's configuration parameters, - such as the ones that cause the <link linkend="snapshot-daemon">snapshot daemon</link> - to run on the master. To get the same behavior, - one would have to set the relevant parameters explicitly - so that they are the same on both master and replica. - </simpara></note> - -</section> -<section xml:id="recovering-from-a-degraded-state"> - <title>Recovering from a degraded state</title> - <para> - "Degraded state" is a situation when the master becomes - unavailable -- due to hardware or network failure, or due to a - programming bug. There is no automatic way for a replica to detect - that the master is gone for good, since sources of failure and - replication environments vary significantly. - So the detection of degraded state requires a human inspection. - </para> - <para> - However, once a master failure is detected, the recovery - is simple: declare that the replica is now the new master, - by saying <code>box.cfg{... listen=URI}</code>. - Then, if there are updates on the old master that were not - propagated before the old master went down, they would have - to be re-applied manually. - </para> - </section> - <section> - <title>Instructions for quick startup of a new two-server simple cluster</title> -<para> -Step 1. Start the first server thus:<programlisting><userinput>box.cfg{listen=<replaceable>uri#1</replaceable>}</userinput> -<userinput>box.schema.user.grant('guest','read,write,execute','universe') -- replace with more restrictive request</userinput> -<userinput>box.snapshot()</userinput></programlisting>... Now a new cluster exists. -</para> -<para> -Step 2. Check where the second server's files will go by looking at -its directories (<olink targetptr="snap_dir">snap_dir</olink> for snapshot files, -<olink targetptr="wal_dir">wal_dir</olink> for .xlog files). They must be empty -- -when the second server joins for the first time, it has to -be working with a clean slate so that the initial copy of -the first server's databases can happen without conflicts. -</para> -<para> -Step 3. Start the second server thus:<programlisting><userinput>box.cfg{listen=<replaceable>uri#2</replaceable>, replication_source=<replaceable>uri#1</replaceable>}</userinput></programlisting> -... where uri#1 = the URI that the first server is listening on. -</para> -<para> -That's all. -</para> -<para> -In this configuration, the first server is the "master" and -the second server is the "replica". Henceforth every change -that happens on the master will be visible on the replica. -A simple two-server cluster with the master on one computer -and the replica on a different computer is very common and -provides two benefits: FAILOVER (because if the master goes -down then the replica can take over), or LOAD BALANCING -(because clients can connect to either the master or the -replica for select requests). -</para> -</section> - -<section> -<title>Master-Master Replication</title> -<para> - In the simple master-replica configuration, the master's - changes are seen by the replica, but not vice versa, - because the master was specified as the sole replication source. - Starting with Tarantool 1.6, it's possible to go both ways. - Starting with the simple configuration, the first server has to say: - <code>box.cfg{replication_source=<replaceable>uri#2</replaceable>}</code>. - This request can be performed at any time. - </para> - <para> - In this configuration, both servers are "masters" and - both servers are "replicas". Henceforth every change - that happens on either server will be visible on the other. - The failover benefit is still present, and the load-balancing - benefit is enhanced (because clients can connect to either - server for data-change requests as well as select requests). - </para> - <para> - If two operations for the same tuple take place "concurrently" - (which can involve a long interval because replication is asynchronous), - and one of the operations is <code>delete</code> or <code>replace</code>, - there is a possibility that servers will end up with different - contents. - </para> -</section> -<section> - <title>All the "What If?" Questions</title> - <para> - <emphasis>What if there are more than two servers with master-master?</emphasis> - ... On each server, specify the replication_source for all - the others. For example, server #3 would have a request: - <code>box.cfg{replication_source=<replaceable>uri#1</replaceable>, replication_source=<replaceable>uri#2</replaceable>}</code>. - </para> - <para> - <emphasis>What if a a server should be taken out of the cluster?</emphasis> - ... Run box.cfg{} again specifying a blank replication source: - <code>box.cfg{replication_source=''}</code>. - </para> - <para> - <emphasis>What if a server leaves the cluster?</emphasis> - ... The other servers carry on. If the wayward server rejoins, - it will receive all the updates that the other servers made - while it was away. - </para> - <para> - <emphasis>What if two servers both change the same tuple?</emphasis> - ... The last changer wins. For example, suppose that server#1 changes - the tuple, then server#2 changes the tuple. In that case server#2's - change overrides whatever server#1 did. In order to - keep track of who came last, Tarantool implements a - <link xlink:href="https://en.wikipedia.org/wiki/Vector_clock">vector clock</link>. - </para> - <para> - <emphasis>What if a master disappears and the replica must take over?</emphasis> - ... A message will appear on the replica stating that the - connection is lost. The replica must now become independent, - which can be done by saying - <code>box.cfg{replication_source=''}</code>. - </para> - <para> - <emphasis>What if it's necessary to know what cluster a server is in?</emphasis> - ... The identification of the cluster is a UUID which is generated - when the first master starts for the first time. This UUID is - stored in a tuple of the _<code>_cluster</code> system space, - and in a tuple of the <code>_schema</code> system space. So to - see it, say: - <code>box.space._schema:select{'cluster'}</code> - </para> - <para> - <emphasis>What if one of the server's files is corrupted or deleted?</emphasis> - ... Stop the server, destroy all the database files (the - ones with extension "snap" or "xlog" or ".inprogress"), - restart the server, and catch up with the master by contacting it again - (just say <code>box.cfg{...replication_source=...}</code>). - </para> - <para> - <emphasis>What if replication causes security concerns?</emphasis> - ... Prevent unauthorized replication sources by associating a password - with every user that has access privileges for the relevant spaces. - That way, the <link linkend="URI">URI</link> for the replication_source parameter - will always have to have the long form <code>replication_source='username:password@host:port'</code>. - </para> - </section> - <section> - <title>Hands-On Replication Tutorial</title> - <para> - After following the steps here, - an administrator will have experience - creating a cluster and adding a replica. - </para> - <para> - Start two shells. Put them side by side on the screen. - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry>______________TERMINAL #1______________</entry><entry>______________TERMINAL #2______________</entry></row> - </thead> - <tbody> - <row><entry><programlisting><prompt>$</prompt></programlisting></entry> - <entry><programlisting><prompt>$</prompt></programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - On the first shell, which we'll call Terminal #1, - execute these commands: -<programlisting> -<userinput># Terminal 1</userinput> -<userinput>mkdir -p ~/tarantool_test_node_1</userinput> -<userinput>cd ~/tarantool_test_node_1</userinput> -<userinput>rm -R ~/tarantool_test_node_1/*</userinput> -<userinput>~/tarantool/src/tarantool</userinput> -<userinput>box.cfg{listen=3301}</userinput> -<userinput>box.schema.user.create('replicator', {password = 'password'})</userinput> -<userinput>box.schema.user.grant('replicator','read,write','universe')</userinput> -<userinput>box.space._cluster:select({0},{iterator='GE'})</userinput> -</programlisting> -</para> -<para> -The result is that a new cluster is set up, and -the UUID is displayed. -Now the screen looks like this: (except that UUID values are always different): - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting>$ <userinput># Terminal 1</userinput> -$ <userinput>mkdir -p ~/tarantool_test_node_1</userinput> -$ <userinput>cd ~/tarantool_test_node_1</userinput> -~/tarantool_test_node_1$ <userinput>rm -R ~/tarantool_test_node_1/*</userinput> -~/tarantool_test_node_1$ <userinput>~/tarantool/src/tarantool</userinput> -~/tarantool/src/tarantool: version 1.6.3-1724-g033ed69 -type 'help' for interactive help -tarantool> <userinput>box.cfg{listen=3301}</userinput> -... ... -tarantool> <userinput>box.schema.user.create('replicator', {password = 'password'})</userinput> -2014-10-13 11:12:56.052 [25018] wal I> creating `./00000000000000000000.xlog.inprogress' ---- -... -tarantool> <userinput>box.schema.user.grant('replicator','read,write','universe')</userinput> ---- -... -tarantool> <userinput>box.space._cluster:select({0},{iterator='GE'})</userinput> ---- -- - [1, '6190d919-1133-4452-b123-beca0b178b32'] -... -</programlisting></entry> - <entry><programlisting>$ - - - - - - - - - - - - - - -</programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - -On the second shell, which we'll call Terminal #2, -execute these commands:<programlisting> -<userinput># Terminal 2</userinput> -<userinput>mkdir -p ~/tarantool_test_node_2</userinput> -<userinput>cd ~/tarantool_test_node_2</userinput> -<userinput>rm -R ~/tarantool_test_node_2/*</userinput> -<userinput>~/tarantool/src/tarantool</userinput> -<userinput>box.cfg{listen=3302, replication_source='replicator:password@localhost:3301'}</userinput> -<userinput>box.space._cluster:select({0},{iterator='GE'})</userinput></programlisting> -The result is that a replica is set up. -Messages appear on Terminal #1 confirming that the -replica has connected and that the WAL contents -have been shipped to the replica. -Messages appear on Terminal #2 showing that -replication is starting. -Also on Terminal#2 the _cluster UUID value is displayed, and it is -the same as the _cluster UUID value that -was displayed on Terminal #1, because both -servers are in the same cluster. - - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting>... ... -tarantool> box.space._cluster:select({0},{iterator='GE'}) ---- -- - [1, '6190d919-1133-4452-b123-beca0b178b32'] -... -tarantool> 2014-10-13 11:20:08.691 [25020] main/101/spawner I> created a replication relay: pid = 25583 -2014-10-13 11:20:08.691 [25583] main/101/relay/127.0.0.1:50883 I> recovery start -2014-10-13 11:20:08.691 [25583] main/101/relay/127.0.0.1:50883 I> recovering from `./00000000000000000000.snap' -2014-10-13 11:20:08.692 [25583] main/101/relay/127.0.0.1:50883 I> snapshot sent -2014-10-13 11:20:08.789 [25020] main/101/spawner I> created a replication relay: pid = 25585 -2014-10-13 11:20:08.890 [25585] main/101/relay/127.0.0.1:50884 I> recover from `./00000000000000000000.xlog' -</programlisting></entry> -<entry><programlisting><prompt>$</prompt> <userinput># Terminal 2</userinput> -~/tarantool_test_node_2$ <userinput>mkdir -p ~/tarantool_test_node_2</userinput> -~/tarantool_test_node_2$ <userinput>cd ~/tarantool_test_node_2</userinput> -~/tarantool_test_node_2$ <userinput>rm -R ~/tarantool_test_node_2/*</userinput> -~/tarantool_test_node_2$ <userinput>~/tarantool/src/tarantool</userinput> -/home/username/tarantool/src/tarantool: version 1.6.3-1724-g033ed69 -type 'help' for interactive help -tarantool> <userinput>box.cfg{listen=3302, replication_source='replicator:password@localhost:3301'}</userinput> -... ... ---- -... -tarantool> <userinput>box.space._cluster:select({0},{iterator='GE'})</userinput> -2014-10-13 11:20:08.789 [25579] main/103/replica/localhost:3301 C> connected to 127.0.0.1:3301 -2014-10-13 11:20:08.789 [25579] main/103/replica/localhost:3301 I> authenticated -2014-10-13 11:20:08.901 [25579] wal I> creating `./00000000000000000000.xlog.inprogress' ---- -- - [1, '6190d919-1133-4452-b123-beca0b178b32'] - - [2, '236230b8-af3e-406b-b709-15a60b44c20c'] -...</programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - -On Terminal #1, execute these requests: -<programlisting><userinput>s = box.schema.space.create('tester')</userinput> -<userinput>i = s:create_index('primary', {})</userinput> -<userinput>s:insert{1,'Tuple inserted on Terminal #1'}</userinput></programlisting> -Now the screen looks like this: - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting>... ... -tarantool> 2014-10-13 11:20:08.691 [25020] main/101/spawner I> created a replication relay: pid = 25583 -2014-10-13 11:20:08.691 [25583] main/101/relay/127.0.0.1:50883 I> recovery start -2014-10-13 11:20:08.691 [25583] main/101/relay/127.0.0.1:50883 I> recovering from `./00000000000000000000.snap' -2014-10-13 11:20:08.692 [25583] main/101/relay/127.0.0.1:50883 I> snapshot sent -2014-10-13 11:20:08.789 [25020] main/101/spawner I> created a replication relay: pid = 25585 -2014-10-13 11:20:08.890 [25585] main/101/relay/127.0.0.1:50884 I> recover from `./00000000000000000000.xlog' ---- -... -tarantool> <userinput>s = box.schema.space.create('tester')</userinput> ---- -... -tarantool> <userinput>i = s:create_index('primary', {})</userinput> ---- -... -tarantool> <userinput>s:insert{1,'Tuple inserted on Terminal #1'}</userinput> ---- -- [1, 'Tuple inserted on Terminal #1'] -... -</programlisting></entry> - <entry><programlisting><prompt>$ # Terminal 2 -~/tarantool_test_node_2$ mkdir -p ~/tarantool_test_node_2 -~/tarantool_test_node_2$ cd ~/tarantool_test_node_2 -~/tarantool_test_node_2$ rm -R ~/tarantool_test_node_2/* -~/tarantool_test_node_2$ ~/tarantool/src/tarantool -/home/username/tarantool/src/tarantool: version 1.6.3-1724-g033ed69 -type 'help' for interactive help -tarantool> box.cfg{listen=3302, replication_source='replicator:password@localhost:3301'} -... ... ---- -... -tarantool> box.space._cluster:select({0},{iterator='GE'}) -2014-10-13 11:20:08.789 [25579] main/103/replica/localhost:3301 C> connected to 127.0.0.1:3301 -2014-10-13 11:20:08.789 [25579] main/103/replica/localhost:3301 I> authenticated -2014-10-13 11:20:08.901 [25579] wal I> creating `./00000000000000000000.xlog.inprogress' ---- -- - [1, '6190d919-1133-4452-b123-beca0b178b32'] - - [2, '236230b8-af3e-406b-b709-15a60b44c20c'] -...</prompt></programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - -The creation and insertion were successful on Terminal #1. -Nothing has happened on Terminal #2. -</para> -<para> -On Terminal #2, execute these requests:<programlisting> -<userinput>s = box.space.tester</userinput> -<userinput>s:select({1},{iterator='GE'})</userinput> -<userinput>s:insert{2,'Tuple inserted on Terminal #2'}</userinput></programlisting> -Now the screen looks like this: - - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting><prompt>... -tarantool> 2014-10-13 11:20:08.691 [25020] main/101/spawner I> created a replication relay: pid = 25583 -2014-10-13 11:20:08.691 [25583] main/101/relay/127.0.0.1:50883 I> recovery start -2014-10-13 11:20:08.691 [25583] main/101/relay/127.0.0.1:50883 I> recovering from `./00000000000000000000.snap' -2014-10-13 11:20:08.692 [25583] main/101/relay/127.0.0.1:50883 I> snapshot sent -2014-10-13 11:20:08.789 [25020] main/101/spawner I> created a replication relay: pid = 25585 -2014-10-13 11:20:08.890 [25585] main/101/relay/127.0.0.1:50884 I> recover from `./00000000000000000000.xlog' ---- -... -tarantool> s = box.schema.space.create('tester') ---- -... -tarantool> i = s:create_index('primary', {}) ---- -... -tarantool> s:insert{1,'Tuple inserted on Terminal #1'} ---- -- [1, 'Tuple inserted on Terminal #1'] -...</prompt></programlisting></entry> - <entry><programlisting>... ... -tarantool> box.space._cluster:select({0},{iterator='GE'}) -2014-10-13 11:20:08.789 [25579] main/103/replica/localhost:3301 C> connected to 127.0.0.1:3301 -2014-10-13 11:20:08.789 [25579] main/103/replica/localhost:3301 I> authenticated -2014-10-13 11:20:08.901 [25579] wal I> creating `./00000000000000000000.xlog.inprogress' ---- -- - [1, '6190d919-1133-4452-b123-beca0b178b32'] - - [2, '236230b8-af3e-406b-b709-15a60b44c20c'] -... -tarantool> <userinput>s = box.space.tester</userinput> ---- -... -tarantool> <userinput>s:select({1},{iterator='GE'})</userinput> ---- -- - [1, 'Tuple inserted on Terminal #1'] -... -tarantool> <userinput>s:insert{2,'Tuple inserted on Terminal #2'}</userinput> ---- -- [2, 'Tuple inserted on Terminal #2'] -... -</programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - -The selection and insertion were successful on Terminal #2. -Nothing has happened on Terminal #1. -</para> -<para> -On Terminal #1, execute these Tarantool requests and shell commands:<programlisting> -<userinput>os.exit()</userinput> -<userinput>ls -l ~/tarantool_test_node_1</userinput> -<userinput>ls -l ~/tarantool_test_node_2</userinput></programlisting> -Now Tarantool #1 is stopped. -Messages appear on Terminal #2 announcing that fact. -The "ls -l" commands show that both servers have -made snapshots, which have the same size because -they both contain the same tuples. - - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting>... ... -tarantool> s:insert{1,'Tuple inserted on Terminal #1'} ---- -- [1, 'Tuple inserted on Terminal #1'] -... -tarantool> <userinput>os.exit()</userinput> -2014-10-13 11:45:20.455 [25585] main/101/relay/127.0.0.1:50884 I> done `./00000000000000000000.xlog' -2014-10-13 11:45:20.531 [25020] main/101/spawner I> Exiting: master shutdown -2014-10-13 11:45:20.531 [25020] main/101/spawner I> sending signal 15 to 1 children -2014-10-13 11:45:20.531 [25020] main/101/spawner I> waiting for children for up to 5 seconds -~/tarantool_test_node_1$ <userinput>ls -l ~/tarantool_test_node_1</userinput> -total 8 --rw-rw-r-- 1 1781 Oct 13 11:12 00000000000000000000.snap --rw-rw-r-- 1 518 Oct 13 11:45 00000000000000000000.xlog -~/tarantool_test_node_1$ <userinput>ls -l ~/tarantool_test_node_2/</userinput> -total 8 --rw-rw-r-- 1 1781 Oct 13 11:20 00000000000000000000.snap --rw-rw-r-- 1 588 Oct 13 11:38 00000000000000000000.xlog -~/tarantool_test_node_1$ -</programlisting></entry> - <entry><programlisting><prompt>... ... -tarantool> s:select({1},{iterator='GE'}) ---- -- - [1, 'Tuple inserted on Terminal #1'] -... -tarantool> s:insert{2,'Tuple inserted on Terminal #2'} ---- -- [2, 'Tuple inserted on Terminal #2'] -... -tarantool> 2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> can't read row -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 !> SystemError -unexpected EOF when reading from socket, -called on fd 10, aka 127.0.0.1:50884, peer of 127.0.0.1:3301: Broken pipe -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> will retry every 1 second -</prompt></programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - -On Terminal #2, ignore the repeated messages saying "failed to connect", and execute these requests:<programlisting> -<userinput>box.space.tester:select({0},{iterator='GE'})</userinput> -<userinput>box.space.tester:insert{3,'Another'}</userinput></programlisting> -Now the screen looks like this (ignoring the repeated messages saying "failed to connect"): - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting><prompt>... ... -tarantool> s:insert{1,'Tuple inserted on Terminal #1'} ---- -- [1, 'Tuple inserted on Terminal #1'] -... -tarantool> os.exit() -2014-10-13 11:45:20.455 [25585] main/101/relay/127.0.0.1:50884 I> done `./00000000000000000000.xlog' -2014-10-13 11:45:20.531 [25020] main/101/spawner I> Exiting: master shutdown -2014-10-13 11:45:20.531 [25020] main/101/spawner I> sending signal 15 to 1 children -2014-10-13 11:45:20.531 [25020] main/101/spawner I> waiting for children for up to 5 seconds -~/tarantool_test_node_1$ ls -l ~/tarantool_test_node_1 -total 8 --rw-rw-r-- 1 1781 Oct 13 11:12 00000000000000000000.snap --rw-rw-r-- 1 518 Oct 13 11:45 00000000000000000000.xlog -~/tarantool_test_node_1$ ls -l ~/tarantool_test_node_2/ -total 8 --rw-rw-r-- 1 1781 Oct 13 11:20 00000000000000000000.snap --rw-rw-r-- 1 588 Oct 13 11:38 00000000000000000000.xlog -~/tarantool_test_node_1$ -</prompt></programlisting></entry> - <entry><programlisting>... ... -tarantool> s:insert{2,'Tuple inserted on Terminal #2'} ---- -- [2, 'Tuple inserted on Terminal #2'] -... -tarantool> 2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> can't read row -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 !> SystemError -unexpected EOF when reading from socket, -called on fd 10, aka 127.0.0.1:50884, peer of 127.0.0.1:3301: Broken pipe -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> will retry every 1 second -tarantool> <userinput>box.space.tester:select({0},{iterator='GE'})</userinput> ---- -- - [1, 'Tuple inserted on Terminal #1'] - - [2, 'Tuple inserted on Terminal #2'] -... -tarantool> <userinput>box.space.tester:insert{3,'Another'}</userinput> ---- -- [3, 'Another'] -... -</programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - -Terminal #2 has done a select and an insert, -even though Terminal #1 is down. -</para> -<para> -On Terminal #1 execute these commands:<programlisting> -<userinput>~/tarantool/src/tarantool</userinput> -<userinput>box.cfg{listen=3301}</userinput> -<userinput>box.space.tester:select({0},{iterator='GE'})</userinput></programlisting> -Now the screen looks like this (ignoring the repeated messages on terminal #2 saying "failed to connect"): - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting>... ... -tarantool> s:insert{1,'Tuple inserted on Terminal #1'} ---- -- [1, 'Tuple inserted on Terminal #1'] -... -tarantool> os.exit() -2014-10-13 11:45:20.455 [25585] main/101/relay/127.0.0.1:50884 I> done `./00000000000000000000.xlog' -2014-10-13 11:45:20.531 [25020] main/101/spawner I> Exiting: master shutdown -2014-10-13 11:45:20.531 [25020] main/101/spawner I> sending signal 15 to 1 children -2014-10-13 11:45:20.531 [25020] main/101/spawner I> waiting for children for up to 5 seconds -~/tarantool_test_node_1$ ls -l ~/tarantool_test_node_1 -total 8 --rw-rw-r-- 1 1781 Oct 13 11:12 00000000000000000000.snap --rw-rw-r-- 1 518 Oct 13 11:45 00000000000000000000.xlog -~/tarantool_test_node_1$ ls -l ~/tarantool_test_node_2/ -total 8 --rw-rw-r-- 1 1781 Oct 13 11:20 00000000000000000000.snap --rw-rw-r-- 1 588 Oct 13 11:38 00000000000000000000.xlog -~/tarantool_test_node_1$ <userinput>~/tarantool/src/tarantool</userinput> -/home/username/tarantool/src/tarantool: version 1.6.3-515-g0a06cce -type 'help' for interactive help -tarantool> <userinput>box.cfg{listen=3301}</userinput> -... ... ---- -... -tarantool> <userinput>box.space.tester:select({0},{iterator='GE'})</userinput> -2014-10-13 12:01:55.615 [28989] main/101/spawner I> created a replication relay: pid = 28992 -2014-10-13 12:01:55.716 [28992] main/101/relay/127.0.0.1:51892 I> recover from `./00000000000000000000.xlog' -2014-10-13 12:01:55.716 [28992] main/101/relay/127.0.0.1:51892 I> done `./00000000000000000000.xlog' ---- -- - [1, 'Tuple inserted on Terminal #1'] -... -</programlisting></entry> - <entry><programlisting><prompt>... ... -tarantool> s:insert{2,'Tuple inserted on Terminal #2'} ---- -- [2, 'Tuple inserted on Terminal #2'] -... -tarantool> 2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> can't read row -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 !> SystemError -unexpected EOF when reading from socket, -called on fd 10, aka 127.0.0.1:50884, peer of 127.0.0.1:3301: Broken pipe -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> will retry every 1 second -tarantool> box.space.tester:select({0},{iterator='GE'}) ---- -- - [1, 'Tuple inserted on Terminal #1'] - - [2, 'Tuple inserted on Terminal #2'] -... -tarantool> box.space.tester:insert{3,'Another'} ---- -- [3, 'Another'] -... -tarantool> -2014-10-13 12:01:55.614 [25579] main/103/replica/localhost:3301 C> connected to 127.0.0.1:3301 -2014-10-13 12:01:55.614 [25579] main/103/replica/localhost:3301 I> authenticated -</prompt></programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - - -The master has reconnected to the cluster, -and has NOT found what the replica wrote -while the master was away. That is not a -surprise -- the replica has not been asked -to act as a replication source. -</para> -<para> -On Terminal #1, say:<programlisting> -<userinput>box.cfg{replication_source='replicator:password@localhost:3302'}</userinput> -<userinput>box.space.tester:select({0},{iterator='GE'})</userinput></programlisting> -The screen now looks like this: - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry align="center">TERMINAL #1</entry><entry align="center">TERMINAL #2</entry></row> - </thead> - <tbody> - <row><entry><programlisting>... ... -~/tarantool_test_node_1$ ~/tarantool/src/tarantool -~/tarantool: version 1.6.3-1724-g033ed69 -type 'help' for interactive help -tarantool> box.cfg{listen=3301} -... ... ---- -... -tarantool> box.space.tester:select({0},{iterator='GE'}) -2014-10-13 12:01:55.615 [28989] main/101/spawner I> created a replication relay: pid = 28992 -2014-10-13 12:01:55.716 [28992] main/101/relay/127.0.0.1:51892 I> recover from `./00000000000000000000.xlog' -2014-10-13 12:01:55.716 [28992] main/101/relay/127.0.0.1:51892 I> done `./00000000000000000000.xlog' - ---- -- - [1, 'Tuple inserted on Terminal #1'] -... -tarantool> <userinput>box.cfg{replication_source='replicator:password@localhost:3302'}</userinput> -2014-10-13 12:10:21.485 [28987] main/101/interactive C> starting replication from localhost:3302 ---- -... -2014-10-13 12:10:21.487 [28987] main/104/replica/localhost:3302 C> connected to 127.0.0.1:3302 -2014-10-13 12:10:21.487 [28987] main/104/replica/localhost:3302 I> authenticated -tarantool> <userinput>box.space.tester:select({0},{iterator='GE'})</userinput> -2014-10-13 12:10:21.592 [28987] wal I> creating `./00000000000000000006.xlog.inprogress' -2014-10-13 12:10:21.617 [28992] main/101/relay/127.0.0.1:51892 I> recover from `./00000000000000000006.xlog' ---- -- - [1, 'Tuple inserted on Terminal #1'] - - [2, 'Tuple inserted on Terminal #2'] - - [3, 'Another'] -... -</programlisting></entry> - <entry><programlisting><prompt>... ... - tarantool> s:insert{2,'Tuple inserted on Terminal #2'} ---- -- [2, 'Tuple inserted on Terminal #2'] -... -tarantool> 2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> can't read row -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 !> SystemError -unexpected EOF when reading from socket, -called on fd 10, aka 127.0.0.1:50884, peer of 127.0.0.1:3301: Broken pipe -2014-10-13 11:45:20.532 [25579] main/103/replica/localhost:3301 I> will retry every 1 second -tarantool> box.space.tester:select({0},{iterator='GE'}) ---- -- - [1, 'Tuple inserted on Terminal #1'] - - [2, 'Tuple inserted on Terminal #2'] -... -tarantool> box.space.tester:insert{3,'Another'} ---- -- [3, 'Another'] -... -tarantool> -2014-10-13 12:01:55.614 [25579] main/103/replica/localhost:3301 C> connected to 127.0.0.1:3301 -2014-10-13 12:01:55.614 [25579] main/103/replica/localhost:3301 I> authenticated -2014-10-13 12:10:21.488 [25581] main/101/spawner I> created a replication relay: pid = 29632 -2014-10-13 12:10:21.592 [29632] main/101/relay/127.0.0.1:45908 I> recover from `./00000000000000000000.xlog' -</prompt></programlisting></entry></row> - </tbody> - </tgroup> - </informaltable> - -This shows that the two servers are once -again in synch, and that each server sees -what the other server wrote. -</para> -<para> -To clean up, say "os.exit()" on both -Terminal #1 and Terminal #2, and then -on either terminal say:<programlisting> -<userinput>cd ~</userinput> -<userinput>rm -R ~/tarantool_test_node_1</userinput> -<userinput>rm -R ~/tarantool_test_node_2</userinput></programlisting> -</para> - - -</section> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/server-administration.xml b/doc/user/server-administration.xml deleted file mode 100644 index fc95264abb70bbdf5872c48cbe4e4326cd21cf55..0000000000000000000000000000000000000000 --- a/doc/user/server-administration.xml +++ /dev/null @@ -1,467 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="server-administration"> -<title>Server administration</title> -<para> - Typical server administration tasks include starting and stopping - the server, reloading configuration, taking snapshots, log rotation. -</para> -<section xml:id="signal-handling"> -<title>Server signal handling</title> -<para> - 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 only be killed with SIGKILL (this signal can not be ignored). -</para> -</section> - -<section xml:id="utility-tarantool"> - -<title>Utility <code>tarantool</code> — using the server as a client</title> - -<para> -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> -<bridgehead renderas="sect4">Conventions used in this section</bridgehead> - -Tokens are character sequences which are treated as syntactic units within requests. - -Square brackets <code>[</code> and <code>]</code> enclose optional syntax. -Three dots in a row <code>...</code> mean the preceding tokens may be repeated. -A vertical bar <code>|</code> means the preceding and following tokens are mutually exclusive alternatives. -</para> - -<para> -<bridgehead renderas="sect4">Options when starting client from the command line</bridgehead> - -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 "box.cfg{...listen=...}" or "box.listen(...)" 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-help" xreflabel="utility-tarantool-help">--help</term> - <listitem><para> - Syntax: short form: <code>-?</code> - long form: <code>--h[elp]</code>. - Effect: Client displays a help message including a list of options. - Example: <code>--help</code> - 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> - Syntax: short form: <code>-V</code> - long form: <code>--v[ersion]</code>. - Effect: Client displays version information. - Example: <code>--version</code> - Notes: The program stops after displaying the version. - </para></listitem> - </varlistentry> -</variablelist> - -<para> -<bridgehead renderas="sect4">Tokens, requests, and special key combinations</bridgehead> -</para> - -<para> -Procedure identifiers are: Any sequence of letters, digits, or underscores which is - legal according to the rules for Lua identifiers. - Procedure identifiers are also called function names. - Notes: function names are case insensitive so <code>insert</code> and <code>Insert</code> are not the same thing. -</para> -<para> -String literals are: Any sequence of zero or more characters enclosed in single quotes. - Double quotes are legal but single quotes are preferred. - Enclosing in double square brackets is good for multi-line strings as described in - <link xlink:href="http://www.lua.org/pil/2.4.html">Lua documentation</link>. - Examples: 'Hello, world', 'A', [[A\B!]]. -</para> -<para> -Numeric literals are: Character sequences containing only digits, optionally preceded by + or -. - Examples: 55, -. - Notes: Tarantool NUM data type is unsigned, so -1 is understood as a large unsigned number. -</para> -<para> -Single-byte tokens are: * or , or ( or ). - Examples: * , ( ). -</para> -<para> -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 xml:id="utility-tarantool-delim"> -<bridgehead renderas="sect4">Requests</bridgehead> -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 -by default a newline (line feed). -</para> -<para> -For multi-line requests, it is possible to change the end-of-request marker. -Syntax: <code>console = require('console'); console.delimiter(<replaceable>string-literal</replaceable>)</code>. -The string-literal must be a value in single quotes. -Effect: string becomes end-of-request delimiter, so newline alone is not treated as end of request. -To go back to normal mode: <code>console.delimiter('')<replaceable>string-literal</replaceable></code>. -Example:<programlisting>console = require('console'); console.delimiter('!') -function f () - statement_1 = 'a' - statement_2 = 'b' - end! -console.delimiter('')!</programlisting> -</para> - -<para> -For a condensed Backus-Naur Form [BNF] description of the suggested form of client requests, see - <link xlink:href="http://tarantool.org/doc/box-protocol.html"><filename>doc/box-protocol.html</filename></link> - and - <link xlink:href="https://github.com/tarantool/tarantool/blob/master/doc/sql.txt"><filename>doc/sql.txt</filename></link>. -</para> - - -<para> -In <emphasis>interactive</emphasis> mode, one types requests and gets results. -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><userinput>tarantool</userinput> - [ tarantool will display an introductory message including version number here ] -tarantool> <userinput>box.cfg{listen=3301}</userinput> - [ tarantool will display configuration information here ] -tarantool> <userinput>s = box.schema.space.create('tester')</userinput> - [ tarantool may display an in-progress message here ] ---- -... -tarantool> <userinput>s:create_index('primary', {type = 'hash', parts = {1, 'NUM'}})</userinput> ---- -... -tarantool> <userinput>box.space.tester:insert{1,'My first tuple'}</userinput> ---- -- [1, 'My first tuple'] -... -tarantool> <userinput>box.space.tester:select(1)</userinput> ---- -- - [1, 'My first tuple'] -... -tarantool> <userinput>box.space.tester:drop()</userinput> ---- -... -tarantool> <userinput>os.exit()</userinput> -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> -* Many requests return typed objects. - In the case of "box.cfg{listen=3301}", - this result is displayed on the screen. - If the request had assigned the result to a variable, for example - "c = box.cfg{listen=3301}", then - the result would not have been displayed on the screen. -</para> -<para> -* A display of an object always begins with "---" and ends with "...". -</para> -<para> -* 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> - -<section xml:id="tarantoolctl"> -<title>Utility <code>tarantoolctl</code></title> -<para> -With tarantoolctl one can say: "start an instance of the -Tarantool server which runs a single user-written Lua -program, allocating disk resources specifically for -that program, via a standardized deployment method." -If Tarantool was downloaded from source, then the script -is in ~/extra/dist/tarantoolctl. If Tarantool was installed -with Debian or Red Hat installation packages, the script -is renamed <code>tarantoolctl</code> and is in -/usr/bin/tarantoolctl. The script handles such things as: -starting, stopping, rotating logs, logging in to the -application's console, and checking status. -</para> - -<bridgehead renderas="sect4">configuring for tarantoolctl</bridgehead> -<para> -The tarantoolctl script will read a configuration file -named /etc/sysconfig/tarantool, or /etc/default/tarantool. -Most of the settings are similar to the settings -used by <code>box.cfg{...}</code>; however, tarantoolctl -adjusts some of them by adding an application name. -A copy of /etc/sysconfig/tarantool, with defaults for -all settings, would look like this:<programlisting> -default_cfg = { - pid_file = "/var/run/tarantool", - wal_dir = "/var/ lib / tarantool", - snap_dir = "/var/lib/tarantool", - sophia_dir = "/var/lib/tarantool", - logger = "/var/log/tarantool", - username = "tarantool", -} -instance_dir = "/etc/tarantool/instances.enabled"</programlisting> -</para> -<para> -The settings in the above script are: -</para> -<para> -pid_file = The directory for the pid file and control-socket file. -The script will add "/<replaceable>instance-name</replaceable>" to the directory name. -</para> -<para> -wal_dir = The directory for the write-ahead *.xlog files. -The script will add "/<replaceable>instance-name</replaceable>" to the directory-name. -</para> -<para> -snap_dir = The directory for the snapshot *.snap files. -The script will add "/<replaceable>instance-name</replaceable>" to the directory-name. -</para> -<para> -sophia_dir = The directory for the sophia-storage-engine files. -The script will add "/sophia/<replaceable>instance-name</replaceable>" to the directory-name. -</para> -<para> -logger = The place where the application log will go. -The script will add /<replaceable>instance-name</replaceable>.log" to the name. -</para> -<para> -username = the user that runs the tarantool server. -This is the operating-system user name rather than the Tarantool-client user name. -</para> -<para> -instance_dir = the directory where all applications for this host are stored. -The user who writes an application for tarantoolctl must put the application's -source code in this directory, or a symbolic link. For examples in this section the application -name <code>my_app</code> will be used, and its source will have to be in -<code><replaceable>instance_dir</replaceable>/my_app.lua</code>. -</para> - -<bridgehead renderas="sect4">commands for tarantoolctl</bridgehead> -<para> -The command format is <code>tarantoolctl <replaceable>operation</replaceable> application-name</code>, -where <replaceable>operation</replaceable> is one of: <code>start</code>, <code>stop</code>, -<code>status</code>, <code>logrotate</code>, <code>enter</code>. Thus ...<programlisting> -tarantoolctl start my_app -- starts application my_app -tarantoolctl stop my_app -- stops my_app -tarantoolctl enter my_app -- show my_app's admin console, if it has one -tarantoolctl logrotate my_app -- rotate my_app's log files (make new, remove old) -tarantoolctl status my_app -- check my_app's status</programlisting> -</para> - -<bridgehead renderas="sect4">typical code snippets for tarantoolctl</bridgehead> -<para> -A user can check whether my_app is running with these lines:<programlisting> - if tarantoolctl status my_app; then - ... - fi</programlisting> -A user can initiate, for boot time, an init.d set of instructions:<programlisting> - for (each file mentioned in the instance_dir directory): - tarantoolctl start `basename $ file .lua`</programlisting> -A user can set up a further configuration file for log rotation, like this:<programlisting> -/path/to/tarantool/*.log { - daily - size 512k - missingok - rotate 10 - compress - delaycompress - create 0640 tarantool adm - postrotate - /path/to/tarantoolctl logrotate `basename $ 1 .log` - endscript -}</programlisting> -</para> - -<bridgehead renderas="sect4">A detailed example for tarantoolctl</bridgehead> -<para> -The example's objective is: make a temporary directory -where tarantoolctl can start a long-running application -and monitor it. -</para> -<para> -The assumptions are: the root password is known, -the computer is only being used for tests, -the Tarantool server is ready to run but is -not currently running, and -there currently is no directory named tarantool_test. -</para> -<para> -Create a directory named /tarantool_test:<programlisting> -sudo mkdir /tarantool_test</programlisting> -</para> -<para> -Copy tarantoolctl to /tarantool_test. -If you made a source download to ~/tarantool-master, then<programlisting> -sudo cp ~/tarantool-master/extra/dist/tarantoolctl /tarantool_test/tarantoolctl</programlisting> -If the file was named tarantoolctl and placed on /usr/bin/tarantoolctl, then<programlisting> -sudo cp /usr/bin/tarantoolctl /tarantool_test/tarantoolctl</programlisting> -</para> -<para> -Check and possibly change the first line of /tarantool_test/tarantoolctl. -Initially it says<programlisting> -#!/usr/bin/env tarantool</programlisting> -If that is not correct, edit tarantoolctl and change the line. -For example, if the Tarantool server is actually on -/home/user/tarantool-master/src/tarantool, change the line to<programlisting> -#!/usr/bin/env /home/user/tarantool-master/src/tarantool</programlisting> -</para> -<para> -Save a copy of /etc/sysconfig/tarantool, if it exists. -</para> -<para> -Edit /etc/sysconfig/tarantool. -It might be necessary to say sudo mkdir /etc/sysconfig first. -Let the new file contents be:<programlisting> -default_cfg = { - pid_file = "/tarantool_test/my_app.pid", - wal_dir = "/tarantool_test", - snap_dir = "/tarantool_test", - sophia_dir = "/tarantool_test", - logger = "/tarantool_test/log", - username = "tarantool", -} -instance_dir = "/tarantool_test"</programlisting> -</para> -<para> -Make the my_app application file, that is, /tarantool_test/my_app.lua. -Let the file contents be:<programlisting> -box.cfg{listen = 3301} -box.schema.user.passwd('Gx5!') -box.schema.user.grant('guest','read,write,execute','universe') -fiber = require('fiber') -box.schema.space.create('tester') -box.space.tester:create_index('primary',{}) -i = 0 -while 0 == 0 do - fiber.sleep(5) - i = i + 1 - print('insert ' .. i) - box.space.tester:insert{i, 'my_app tuple'} -end</programlisting> -</para> -<para> -Tell tarantoolctl to start the application ...<programlisting> -cd /tarantool_test -sudo ./tarantoolctl start my_app</programlisting> -... expect to see messages indicating that the instance has started. Then ...<programlisting> -ls -l /tarantool_test/my_app</programlisting> -... expect to see the .snap file, .xlog file, and sophia directory. Then ...<programlisting> -less /tarantool_test/log/my_app.log</programlisting> -... expect to see the contents of my_app's log, including error messages, if any. Then ...<programlisting> -cd /tarantool_test -#assume that 'tarantool' invokes the tarantool server -sudo tarantool -box.cfg{} -console = require('console') -console.connect('localhost:3301') -box.space.tester:select({0},{iterator='GE'})</programlisting> -... expect to see several tuples that my_app has created. -</para> -<para> -Stop. The only clean way to stop my_app is with tarantoolctl, thus:<programlisting> -sudo ./tarantoolctl stop my_app</programlisting> -</para> -<para> -Clean up. Restore the original contents of /etc/sysconfig/tarantool, and ...<programlisting> -cd / -sudo rm -R tarantool_test</programlisting> -</para> - -</section> - -<section xml:id="os-install-notes"> -<title>System-specific administration notes</title> -<blockquote><para> - 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>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> - <para> - Starting all instances: service tarantool start - </para> - <para> - Stopping all instances: service tarantool stop - </para> - <para> - Starting/stopping one instance: service tarantool-instance-name start/stop - </para> - </section> - <section xml:id="rpm-based-distros"> - <title>Fedora, RHEL, CentOS</title> - <para> - 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> - 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> - 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> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/space.xml b/doc/user/space.xml deleted file mode 100644 index e89e93ea998d95b28c755563531d19e2a4e698f9..0000000000000000000000000000000000000000 --- a/doc/user/space.xml +++ /dev/null @@ -1,101 +0,0 @@ -<para xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xi="http://www.w3.org/2001/XInclude" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="space"> -<bridgehead>Space settings explained</bridgehead> -Space is a composite parameter, that is, it has properties. -<programlisting language="cpp"> -/* - * Each tuple consists of fields. Field types may be - * integers, floats, or strings. - * Tarantool is interested in field types only inasmuch as - * it needs to build indexes on fields. Two indexed field - * types are supported. -enum { STR, NUM } field_type; - * An index can cover one or more fields. - */ - -struct index_field_t { - unsigned int fieldno; - enum field_type type; -}; - -/* - * HASH and TREE and BITSET index types are supported. - */ - -enum { HASH, TREE, BITSET } index_type; - -struct index_t { - index_field_t key_field[]; - enum index_type type; - /* Secondary index may be non-unique */ - bool unique; -}; - -struct space_t -{ - /* A space can be quickly disabled and re-enabled at run time. */ - bool enabled; - /* - * If cardinality is given, each tuple in the space must have exactly - * this many fields. - */ - unsigned int arity; - /* estimated_rows is only used for HASH indexes, to preallocate memory. */ - unsigned int estimated_rows; - struct index_t index[]; -}; -</programlisting> -The way a space is defined in a configuration file is similar to how -one would initialize a C structure in a program. For example, -a minimal storage configuration looks like the following: -<programlisting language="c"> -space[0].enabled = 1 -space[0].index[0].type = HASH -space[0].index[0].unique = 1 -space[0].index[0].key_field[1].fieldno = 1 -space[0].index[0].key_field[1].type = NUM64 -</programlisting> -The parameters listed above are mandatory. Other space -properties are set in the same way. -An alternative syntax, mainly useful when defining large spaces, exists: -<programlisting language="c"> -space[0] = { - enabled = 1, - index = [ - { - type = HASH, - key_field = [ - { - fieldno = 1, - type = NUM64 - } - ] - } - ] -} -</programlisting> -When defining a space, -please be aware of these restrictions: -<itemizedlist> - <listitem><simpara>at least one space must be - configured,</simpara></listitem> - <listitem><simpara>each configured space needs at least one - unique index, - </simpara></listitem> - <listitem><simpara>"unique" property doesn't have a default, and - must be set explicitly, - </simpara></listitem> - <listitem><simpara>space configuration can not be changed - dynamically, currently you need to restart the server even to - disable or enable a space, - </simpara></listitem> - <listitem><simpara>HASH indexes can not be non-unique. - </simpara></listitem> -</itemizedlist> -</para> -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/target.db b/doc/user/target.db deleted file mode 100644 index 8eefc54c5319b1effd04c5358cdd2b6ecf9ec13c..0000000000000000000000000000000000000000 --- a/doc/user/target.db +++ /dev/null @@ -1,7 +0,0 @@ -<div element="book" href="#tarantool-user-guide" number="" targetptr="tarantool-user-guide"><ttl>Tarantool User Guide, version 1.6.1-279-ga84cec2</ttl><xreftext>Tarantool User Guide, version 1.6.1-279-ga84cec2</xreftext><div element="chapter" href="#preface" number="1" targetptr="preface"><ttl>Preface</ttl><xreftext>Chapter 1, <i>Preface</i></xreftext><div element="section" href="#tarantool-overview" number="" targetptr="tarantool-overview"><ttl>Tarantool: an overview</ttl><xreftext>the section called “Tarantool: an overviewâ€</xreftext></div><div element="section" href="#manual-conventions" number="" targetptr="manual-conventions"><ttl>Conventions</ttl><xreftext>the section called “Conventionsâ€</xreftext></div><div element="section" href="#reporting-bugs" number="" targetptr="reporting-bugs"><ttl>Reporting bugs</ttl><xreftext>the section called “Reporting bugsâ€</xreftext></div></div><div element="chapter" href="#getting-started" number="2" targetptr="getting-started"><ttl>Getting started</ttl><xreftext>Chapter 2, <i>Getting started</i></xreftext><div element="section" href="#getting-started-binary" number="" targetptr="getting-started-binary"><ttl>Downloading and installing a binary package</ttl><xreftext>the section called “Downloading and installing a binary packageâ€</xreftext></div><div element="section" href="#getting-started-source" number="" targetptr="getting-started-source"><ttl>Downloading and building a source package</ttl><xreftext>the section called “Downloading and building a source packageâ€</xreftext></div><div element="section" href="#getting-started-start-stop" number="" targetptr="getting-started-start-stop"><ttl>Starting Tarantool and making your first database</ttl><xreftext>the section called “Starting Tarantool and making your first databaseâ€</xreftext></div><div element="section" href="#differences-from-older-versions" number="" targetptr="differences-from-older-versions"><ttl>Differences between Tarantool 1.6 and older versions</ttl><xreftext>the section called “Differences between Tarantool 1.6 and older versionsâ€</xreftext></div></div><div element="chapter" href="#data-and-persistence" number="3" targetptr="data-and-persistence"><ttl>Data model and data persistence</ttl><xreftext>Chapter 3, <i>Data model and data persistence</i></xreftext><div element="section" href="#dynamic-data-model" number="" targetptr="dynamic-data-model"><ttl>Dynamic data model</ttl><xreftext>the section called “Dynamic data modelâ€</xreftext></div><div element="section" href="#data-persistence" number="" targetptr="data-persistence"><ttl>Data persistence</ttl><xreftext>the section called “Data persistenceâ€</xreftext></div></div><div element="chapter" href="#language-reference" number="4" targetptr="language-reference"><ttl>Language reference</ttl><xreftext>Chapter 4, <i>Language reference</i></xreftext><div element="section" href="#data-manipulation" number="" targetptr="data-manipulation"><ttl>Data manipulation</ttl><xreftext>the section called “Data manipulationâ€</xreftext></div><div element="section" href="#administrative-console" number="" targetptr="administrative-console"><ttl>Administrative console</ttl><xreftext>the section called “Administrative consoleâ€</xreftext><obj element="term" href="#box.snapshot" number="" targetptr="box.snapshot"><ttl>???TITLE???</ttl><xreftext>box.snapshot()</xreftext></obj><obj element="term" href="#box.cfg.reload" number="" targetptr="box.cfg.reload"><ttl>???TITLE???</ttl><xreftext>box.cfg.reload()</xreftext></obj><obj element="term" href="#box.cfg.show" number="" targetptr="box.cfg.show"><ttl>???TITLE???</ttl><xreftext>box.cfg()</xreftext></obj><obj element="term" href="#box.info" number="" targetptr="box.info"><ttl>???TITLE???</ttl><xreftext>box.info()</xreftext></obj><obj element="term" href="#show-index" number="" targetptr="show-index"><ttl>???TITLE???</ttl><xreftext>SHOW INDEX</xreftext></obj><obj element="term" href="#box.stat.show" number="" targetptr="box.stat.show"><ttl>???TITLE???</ttl><xreftext>box.stat.show()</xreftext></obj><obj element="term" href="#box.slab.info" number="" targetptr="box.slab.info"><ttl>???TITLE???</ttl><xreftext>box.slab.info()</xreftext></obj><obj element="term" href="#box.coredump" number="" targetptr="box.coredump"><ttl>???TITLE???</ttl><xreftext>box.coredump()</xreftext></obj><obj element="term" href="#box.fiber.info" number="" targetptr="box.fiber.info"><ttl>???TITLE???</ttl><xreftext>box.fiber.info()</xreftext></obj><obj element="term" href="#lua-command" number="" targetptr="lua-command"><ttl>???TITLE???</ttl><xreftext> - <span class="tntadmin">...</span> - </xreftext></obj></div><div element="section" href="#stored-procedures" number="" targetptr="stored-procedures"><ttl>Writing stored procedures in Lua</ttl><xreftext>the section called “Writing stored procedures in Luaâ€</xreftext><obj element="filename" href="#init.lua" number="" targetptr="init.lua"><ttl>???TITLE???</ttl><xreftext>init.lua</xreftext></obj><obj element="term" href="#tonumber64" number="" targetptr="tonumber64"><ttl>???TITLE???</ttl><xreftext>tonumber64</xreftext></obj><div element="section" href="#sp-box-library" number="" targetptr="sp-box-library"><ttl>The <code class="code">box</code> library</ttl><xreftext>the section called “The <code class="code">box</code> libraryâ€</xreftext><obj element="table" href="#idp724256" number="4.1"><ttl>Possible types of the values that a function in the box library can return</ttl><xreftext>Table 4.1, “Possible types of the values that a function in the box library can returnâ€</xreftext></obj><obj element="title" href="#function-types" number="" targetptr="function-types"><ttl>Possible types of the values that a function in the box library can return</ttl><xreftext>Table 4.1, “Possible types of the values that a function in the box library can returnâ€</xreftext></obj><obj element="entry" href="#function-type-number" number="" targetptr="function-type-number"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="entry" href="#function-type-string" number="" targetptr="function-type-string"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="entry" href="#function-type-nil" number="" targetptr="function-type-nil"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="entry" href="#function-type-lua-table" number="" targetptr="function-type-lua-table"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="entry" href="#function-type-tuple" number="" targetptr="function-type-tuple"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj></div><div element="section" href="#sp-box" number="" targetptr="sp-box"><ttl>Package <code class="code">box</code></ttl><xreftext>the section called “Package <code class="code">box</code>â€</xreftext><obj element="variablelist" href="#box" number="" targetptr="box"><ttl>???TITLE???</ttl><xreftext>box</xreftext></obj><obj element="emphasis" href="#box.process" number="" targetptr="box.process"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.select" number="" targetptr="box.select"><ttl>???TITLE???</ttl><xreftext>box.select</xreftext></obj><obj element="emphasis" href="#box.insert" number="" targetptr="box.insert"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.select_limit" number="" targetptr="box.select_limit"><ttl>???TITLE???</ttl><xreftext>box.select_limit</xreftext></obj><obj element="emphasis" href="#box.replace" number="" targetptr="box.replace"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.update" number="" targetptr="box.update"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.delete" number="" targetptr="box.delete"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.select_range" number="" targetptr="box.select_range"><ttl>???TITLE???</ttl><xreftext>box.select_range</xreftext></obj><obj element="emphasis" href="#box.select_reverse_range" number="" targetptr="box.select_reverse_range"><ttl>???TITLE???</ttl><xreftext>box.select_reverse_range</xreftext></obj></div><div element="section" href="#sp-box-tuple" number="" targetptr="sp-box-tuple"><ttl>Package <code class="code">box.tuple</code></ttl><xreftext>the section called “Package <code class="code">box.tuple</code>â€</xreftext><obj element="variablelist" href="#box.tuple" number="" targetptr="box.tuple"><ttl>???TITLE???</ttl><xreftext>box.tuple</xreftext></obj></div><div element="section" href="#sp-box-cjson" number="" targetptr="sp-box-cjson"><ttl>Package <code class="code">box.cjson</code></ttl><xreftext>the section called “Package <code class="code">box.cjson</code>â€</xreftext><obj element="variablelist" href="#box.cjson" number="" targetptr="box.cjson"><ttl>???TITLE???</ttl><xreftext>box.cjson</xreftext></obj></div><div element="section" href="#sp-box-space" number="" targetptr="sp-box-space"><ttl>Package <code class="code">box.space</code></ttl><xreftext>the section called “Package <code class="code">box.space</code>â€</xreftext><obj element="variablelist" href="#box.space" number="" targetptr="box.space"><ttl>???TITLE???</ttl><xreftext>box.space</xreftext></obj><obj element="emphasis" href="#box.space.select_range" number="" targetptr="box.space.select_range"><ttl>???TITLE???</ttl><xreftext>box.space[i].select_range()</xreftext></obj><obj element="emphasis" href="#box.space.select_reverse_range" number="" targetptr="box.space.select_reverse_range"><ttl>???TITLE???</ttl><xreftext>box.space.select_reverse_range</xreftext></obj></div><div element="section" href="#sp-box-index" number="" targetptr="sp-box-index"><ttl>Package <code class="code">box.index</code></ttl><xreftext>the section called “Package <code class="code">box.index</code>â€</xreftext><obj element="variablelist" href="#box.index" number="" targetptr="box.index"><ttl>???TITLE???</ttl><xreftext>box.index</xreftext></obj><obj element="emphasis" href="#box.index.iterator" number="" targetptr="box.index.iterator"><ttl>???TITLE???</ttl><xreftext>box.index.iterator(type, ...)</xreftext></obj><obj element="para" href="#iterator-consistency" number="" targetptr="iterator-consistency"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="para" href="#iterator-types" number="" targetptr="iterator-types"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="table" href="#idp1114672" number="4.2"><ttl>Common iterator types</ttl><xreftext>Table 4.2, “Common iterator typesâ€</xreftext></obj><obj element="table" href="#idp983120" number="4.3"><ttl>TREE iterator types</ttl><xreftext>Table 4.3, “TREE iterator typesâ€</xreftext></obj><obj element="table" href="#idp1000912" number="4.4"><ttl>BITSET iterator types</ttl><xreftext>Table 4.4, “BITSET iterator typesâ€</xreftext></obj></div><div element="section" href="#sp-box-fiber" number="" targetptr="sp-box-fiber"><ttl>Package <code class="code">box.fiber</code></ttl><xreftext>the section called “Package <code class="code">box.fiber</code>â€</xreftext><obj element="variablelist" href="#box.fiber" number="" targetptr="box.fiber"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj><obj element="emphasis" href="#box.fiber.id" number="" targetptr="box.fiber.id"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.self" number="" targetptr="box.fiber.self"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.find" number="" targetptr="box.fiber.find"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.create" number="" targetptr="box.fiber.create"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.resume" number="" targetptr="box.fiber.resume"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.yield" number="" targetptr="box.fiber.yield"><ttl>???TITLE???</ttl><xreftext>box.fiber.yield</xreftext></obj><obj element="emphasis" href="#box.fiber.detach" number="" targetptr="box.fiber.detach"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.wrap" number="" targetptr="box.fiber.wrap"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.sleep" number="" targetptr="box.fiber.sleep"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.status" number="" targetptr="box.fiber.status"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.cancel" number="" targetptr="box.fiber.cancel"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.fiber.testcancel" number="" targetptr="box.fiber.testcancel"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj></div><div element="section" href="#sp-box-session" number="" targetptr="sp-box-session"><ttl>Package <code class="code">box.session</code></ttl><xreftext>the section called “Package <code class="code">box.session</code>â€</xreftext></div><div element="section" href="#sp-box-ipc" number="" targetptr="sp-box-ipc"><ttl>Package <code class="code">box.ipc</code> — inter procedure communication</ttl><xreftext>the section called “Package <code class="code">box.ipc</code> — inter procedure communicationâ€</xreftext><obj element="variablelist" href="#box.ipc" number="" targetptr="box.ipc"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj></div><div element="section" href="#sp-box-socket" number="" targetptr="sp-box-socket"><ttl>Package <code class="code">box.socket</code> — TCP and UDP sockets</ttl><xreftext>the section called “Package <code class="code">box.socket</code> — TCP and UDP socketsâ€</xreftext><obj element="variablelist" href="#box.socket" number="" targetptr="box.socket"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj><obj element="table" href="#idp622752" number="4.5"><ttl><code class="code">readline()</code> returns</ttl><xreftext>Table 4.5, “<code class="code">readline()</code> returnsâ€</xreftext></obj></div><div element="section" href="#sp-box-net-box" number="" targetptr="sp-box-net-box"><ttl>Package <code class="code">box.net.box</code> — working with networked Tarantool peers</ttl><xreftext>the section called “Package <code class="code">box.net.box</code> — working with networked Tarantool peersâ€</xreftext><obj element="variablelist" href="#box.net.box" number="" targetptr="box.net.box"><ttl>???TITLE???</ttl><xreftext>???TITLE???</xreftext></obj><obj element="emphasis" href="#box.net.box.new" number="" targetptr="box.net.box.new"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.ping" number="" targetptr="box.net.box.ping"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.close" number="" targetptr="box.net.box.close"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.select" number="" targetptr="box.net.box.select"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.select_limit" number="" targetptr="box.net.box.select_limit"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.select_range" number="" targetptr="box.net.box.select_range"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.insert" number="" targetptr="box.net.box.insert"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.replace" number="" targetptr="box.net.box.replace"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.update" number="" targetptr="box.net.box.update"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.delete" number="" targetptr="box.net.box.delete"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.call" number="" targetptr="box.net.box.call"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="emphasis" href="#box.net.box.timeout" number="" targetptr="box.net.box.timeout"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj></div><div element="section" href="#sp-box-cfg" number="" targetptr="sp-box-cfg"><ttl>Packages <code class="code">box.cfg</code>, - <code class="code">box.info</code>, <code class="code">box.slab</code> and - <code class="code">box.stat</code>: server introspection</ttl><xreftext>the section called “Packages <code class="code">box.cfg</code>, - <code class="code">box.info</code>, <code class="code">box.slab</code> and - <code class="code">box.stat</code>: server introspectionâ€</xreftext><obj element="code" href="#box.cfg" number="" targetptr="box.cfg"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj><obj element="code" href="#box.stat" number="" targetptr="box.stat"><ttl>???TITLE???</ttl><xreftext>???</xreftext></obj></div><div element="section" href="#sp-limitations" number="" targetptr="sp-limitations"><ttl>Limitations of stored procedures</ttl><xreftext>the section called “Limitations of stored proceduresâ€</xreftext></div></div><div element="section" href="#triggers" number="" targetptr="triggers"><ttl>Defining triggers in Lua</ttl><xreftext>the section called “Defining triggers in Luaâ€</xreftext><div element="section" href="#sp-box-session-triggers" number="" targetptr="sp-box-session-triggers"><ttl>Triggers on connect and disconnect</ttl><xreftext>session triggers</xreftext></div></div></div><div element="chapter" href="#replication" number="5" targetptr="replication"><ttl>Replication</ttl><xreftext>Chapter 5, <i>Replication</i></xreftext><div element="section" href="#replication-architecture" number="" targetptr="replication-architecture"><ttl>Replication architecture</ttl><xreftext>the section called “Replication architectureâ€</xreftext></div><div element="section" href="#setting-up-the-master" number="" targetptr="setting-up-the-master"><ttl>Setting up the master</ttl><xreftext>the section called “Setting up the masterâ€</xreftext></div><div element="section" href="#settin-up-a-replica" number="" targetptr="settin-up-a-replica"><ttl>Setting up a replica</ttl><xreftext>the section called “Setting up a replicaâ€</xreftext></div><div element="section" href="#recovering-from-a-degraded-state" number="" targetptr="recovering-from-a-degraded-state"><ttl>Recovering from a degraded state</ttl><xreftext>the section called “Recovering from a degraded stateâ€</xreftext></div></div><div element="chapter" href="#server-administration" number="6" targetptr="server-administration"><ttl>Server administration</ttl><xreftext>Chapter 6, <i>Server administration</i></xreftext><div element="section" href="#signal-handling" number="" targetptr="signal-handling"><ttl>Server signal handling</ttl><xreftext>the section called “Server signal handlingâ€</xreftext></div><div element="section" href="#utility-tarantool" number="" targetptr="utility-tarantool"><ttl>Utility <code class="code">tarantool</code> — the main client</ttl><xreftext>the section called “Utility <code class="code">tarantool</code> — the main clientâ€</xreftext><obj element="term" href="#utility-tarantool-admin-port" number="" targetptr="utility-tarantool-admin-port"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-admin-port</xreftext></obj><obj element="term" href="#utility-tarantool-bin" number="" targetptr="utility-tarantool-bin"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-bin</xreftext></obj><obj element="term" href="#utility-tarantool-cat" number="" targetptr="utility-tarantool-cat"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-cat</xreftext></obj><obj element="term" href="#utility-tarantool-delim" number="" targetptr="utility-tarantool-delim"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-delim</xreftext></obj><obj element="term" href="#utility-tarantool-format" number="" targetptr="utility-tarantool-format"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-format</xreftext></obj><obj element="term" href="#utility-tarantool-from" number="" targetptr="utility-tarantool-from"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-from</xreftext></obj><obj element="term" href="#utility-tarantool-header" number="" targetptr="utility-tarantool-header"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-header</xreftext></obj><obj element="term" href="#utility-tarantool-help" number="" targetptr="utility-tarantool-help"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-help</xreftext></obj><obj element="term" href="#utility-tarantool-host" number="" targetptr="utility-tarantool-host"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-host</xreftext></obj><obj element="term" href="#utility-tarantool-play" number="" targetptr="utility-tarantool-play"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-play</xreftext></obj><obj element="term" href="#utility-tarantool-port" number="" targetptr="utility-tarantool-port"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-port</xreftext></obj><obj element="term" href="#utility-tarantool-rpl" number="" targetptr="utility-tarantool-rpl"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-rpl</xreftext></obj><obj element="term" href="#utility-tarantool-space" number="" targetptr="utility-tarantool-space"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-space</xreftext></obj><obj element="term" href="#utility-tarantool-to" number="" targetptr="utility-tarantool-to"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-to</xreftext></obj><obj element="term" href="#utility-tarantool-version" number="" targetptr="utility-tarantool-version"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-version</xreftext></obj><obj element="term" href="#utility-tarantool-call" number="" targetptr="utility-tarantool-call"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-call</xreftext></obj><obj element="term" href="#utility-tarantool-delete" number="" targetptr="utility-tarantool-delete"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-delete</xreftext></obj><obj element="term" href="#utility-tarantool-exit" number="" targetptr="utility-tarantool-exit"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-exit</xreftext></obj><obj element="term" href="#utility-tarantool-help2" number="" targetptr="utility-tarantool-help2"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-help2</xreftext></obj><obj element="term" href="#utility-tarantool-insert" number="" targetptr="utility-tarantool-insert"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-insert</xreftext></obj><obj element="term" href="#utility-tarantool-loadfile" number="" targetptr="utility-tarantool-loadfile"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-loadfile</xreftext></obj><obj element="term" href="#utility-tarantool-lua" number="" targetptr="utility-tarantool-lua"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-lua</xreftext></obj><obj element="term" href="#utility-tarantool-ping" number="" targetptr="utility-tarantool-ping"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-ping</xreftext></obj><obj element="term" href="#utility-tarantool-quit" number="" targetptr="utility-tarantool-quit"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-quit</xreftext></obj><obj element="term" href="#utility-tarantool-reload" number="" targetptr="utility-tarantool-reload"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-reload</xreftext></obj><obj element="term" href="#utility-tarantool-replace" number="" targetptr="utility-tarantool-replace"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-replace</xreftext></obj><obj element="term" href="#utility-tarantool-save" number="" targetptr="utility-tarantool-save"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-save</xreftext></obj><obj element="term" href="#utility-tarantool-select" number="" targetptr="utility-tarantool-select"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-select</xreftext></obj><obj element="term" href="#utility-tarantool-set" number="" targetptr="utility-tarantool-set"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-set</xreftext></obj><obj element="term" href="#utility-tarantool-setopt" number="" targetptr="utility-tarantool-setopt"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-setopt</xreftext></obj><obj element="term" href="#utility-tarantool-show" number="" targetptr="utility-tarantool-show"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-show</xreftext></obj><obj element="term" href="#utility-tarantool-update" number="" targetptr="utility-tarantool-update"><ttl>???TITLE???</ttl><xreftext>utility-tarantool-update</xreftext></obj></div><div element="section" href="#tarantar" number="" targetptr="tarantar"><ttl>Utility <code class="code">tarantar</code></ttl><xreftext>the section called “Utility <code class="code">tarantar</code>â€</xreftext></div><div element="section" href="#tarancheck" number="" targetptr="tarancheck"><ttl>Utility <code class="code">tarancheck</code></ttl><xreftext>the section called “Utility <code class="code">tarancheck</code>â€</xreftext></div><div element="section" href="#tarantool_deploy" number="" targetptr="tarantool_deploy"><ttl>Utility <code class="code">tarantool_deploy</code></ttl><xreftext>the section called “Utility <code class="code">tarantool_deploy</code>â€</xreftext></div><div element="section" href="#os-install-notes" number="" targetptr="os-install-notes"><ttl>System-specific administration notes</ttl><xreftext>the section called “System-specific administration notesâ€</xreftext><div element="section" href="#Debian" number="" targetptr="Debian"><ttl>Debian GNU/Linux and Ubuntu</ttl><xreftext>the section called “Debian GNU/Linux and Ubuntuâ€</xreftext></div><div element="section" href="#rpm-based-distros" number="" targetptr="rpm-based-distros"><ttl>Fedora, RHEL, CentOS</ttl><xreftext>the section called “Fedora, RHEL, CentOSâ€</xreftext></div><div element="section" href="#FreeBSD" number="" targetptr="FreeBSD"><ttl>FreeBSD</ttl><xreftext>the section called “FreeBSDâ€</xreftext></div><div element="section" href="#mac-os-x" number="" targetptr="mac-os-x"><ttl>Mac OS X</ttl><xreftext>the section called “Mac OS Xâ€</xreftext></div></div></div><div element="chapter" href="#configuration-reference" number="7" targetptr="configuration-reference"><ttl>Configuration reference</ttl><xreftext>Chapter 7, <i>Configuration reference</i></xreftext><div element="section" href="#command-line-options" number="" targetptr="command-line-options"><ttl>Command line options</ttl><xreftext>the section called “Command line optionsâ€</xreftext><obj element="listitem" href="#help-option" number="" targetptr="help-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#version-option" number="" targetptr="version-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="listitem" href="#config-option" number="" targetptr="config-option"><ttl>???TITLE???</ttl><xreftext/></obj><obj element="option" href="#init-storage-option" number="" targetptr="init-storage-option"><ttl>???TITLE???</ttl><xreftext>--init-storage</xreftext></obj></div><div element="section" href="#configuration-file" number="" targetptr="configuration-file"><ttl>The configuration file</ttl><xreftext>configuration file</xreftext><obj element="table" href="#idp2098320" number="7.1"><ttl>Basic parameters</ttl><xreftext>Table 7.1, “Basic parametersâ€</xreftext></obj><obj element="entry" href="#work_dir" number="" targetptr="work_dir"><ttl>???TITLE???</ttl><xreftext>work_dir</xreftext></obj><obj element="entry" href="#script_dir" number="" targetptr="script_dir"><ttl>???TITLE???</ttl><xreftext>script_dir</xreftext></obj><obj element="entry" href="#wal_dir" number="" targetptr="wal_dir"><ttl>???TITLE???</ttl><xreftext>wal_dir</xreftext></obj><obj element="entry" href="#snap_dir" number="" targetptr="snap_dir"><ttl>???TITLE???</ttl><xreftext>snap_dir</xreftext></obj><obj element="entry" href="#bind_ipaddr" number="" targetptr="bind_ipaddr"><ttl>???TITLE???</ttl><xreftext>bind_ipaddr</xreftext></obj><obj element="entry" href="#primary_port" number="" targetptr="primary_port"><ttl>???TITLE???</ttl><xreftext>primary_port</xreftext></obj><obj element="entry" href="#secondary_port" number="" targetptr="secondary_port"><ttl>???TITLE???</ttl><xreftext>secondary_port</xreftext></obj><obj element="entry" href="#admin_port" number="" targetptr="admin_port"><ttl>???TITLE???</ttl><xreftext>admin_port</xreftext></obj><obj element="entry" href="#custom_proc_title" number="" targetptr="custom_proc_title"><ttl>???TITLE???</ttl><xreftext>custom_proc_title</xreftext></obj><obj element="table" href="#idp2157072" number="7.2"><ttl>Configuring the storage</ttl><xreftext>Table 7.2, “Configuring the storageâ€</xreftext></obj><obj element="anchor" href="#slab_alloc_arena" number="" targetptr="slab_alloc_arena"><ttl>???TITLE???</ttl><xreftext>slab_alloc_arena</xreftext></obj><obj element="para" href="#space" number="" targetptr="space"><ttl>???TITLE???</ttl><xreftext>the section called “The configuration fileâ€</xreftext></obj><obj element="table" href="#idp2193104" number="7.3"><ttl>Binary logging and snapshots</ttl><xreftext>Table 7.3, “Binary logging and snapshotsâ€</xreftext></obj><obj element="entry" href="#rows_per_wal" number="" targetptr="rows_per_wal"><ttl>???TITLE???</ttl><xreftext>rows_per_wal</xreftext></obj><obj element="entry" href="#wal_mode" number="" targetptr="wal_mode"><ttl>???TITLE???</ttl><xreftext>wal_mode</xreftext></obj><obj element="table" href="#idp2228480" number="7.4"><ttl>Replication</ttl><xreftext>Table 7.4, “Replicationâ€</xreftext></obj><obj element="entry" href="#replication_port" number="" targetptr="replication_port"><ttl>???TITLE???</ttl><xreftext>replication_port</xreftext></obj><obj element="entry" href="#replication_source" number="" targetptr="replication_source"><ttl>???TITLE???</ttl><xreftext>replication_source</xreftext></obj><obj element="table" href="#idp2247984" number="7.5"><ttl>Networking</ttl><xreftext>Table 7.5, “Networkingâ€</xreftext></obj><obj element="table" href="#idp2264176" number="7.6"><ttl>Logging</ttl><xreftext>Table 7.6, “Loggingâ€</xreftext></obj><obj element="table" href="#idp2289088" number="7.7"><ttl>Hot Standby</ttl><xreftext>Table 7.7, “Hot Standbyâ€</xreftext></obj><obj element="anchor" href="#local_hot_standby" number="" targetptr="local_hot_standby"><ttl>???TITLE???</ttl><xreftext>local_hot_standby</xreftext></obj></div></div><div element="chapter" href="#connectors" number="8" targetptr="connectors"><ttl>Connectors</ttl><xreftext>Chapter 8, <i>Connectors</i></xreftext><div element="section" href="#connector-packet-example" number="" targetptr="connector-packet-example"><ttl>Packet example</ttl><xreftext>the section called “Packet exampleâ€</xreftext></div><div element="section" href="#connector-c" number="" targetptr="connector-c"><ttl>C</ttl><xreftext>the section called “Câ€</xreftext></div><div element="section" href="#connector-erlang" number="" targetptr="connector-erlang"><ttl>Erlang</ttl><xreftext>the section called “Erlangâ€</xreftext></div><div element="section" href="#connector-java" number="" targetptr="connector-java"><ttl>Java</ttl><xreftext>the section called “Javaâ€</xreftext></div><div element="section" href="#connector-node.js" number="" targetptr="connector-node.js"><ttl>node.js</ttl><xreftext>the section called “node.jsâ€</xreftext></div><div element="section" href="#connector-perl" number="" targetptr="connector-perl"><ttl>Perl</ttl><xreftext>the section called “Perlâ€</xreftext></div><div element="section" href="#connector-php" number="" targetptr="connector-php"><ttl>PHP</ttl><xreftext>the section called “PHPâ€</xreftext></div><div element="section" href="#connector-python" number="" targetptr="connector-python"><ttl>Python</ttl><xreftext>the section called “Pythonâ€</xreftext></div><div element="section" href="#connector-ruby" number="" targetptr="connector-ruby"><ttl>Ruby</ttl><xreftext>the section called “Rubyâ€</xreftext></div></div><div element="appendix" href="#proctitle" number="A" targetptr="proctitle"><ttl>Server process titles</ttl><xreftext>Appendix A, <i>Server process titles</i></xreftext></div><div element="appendix" href="#errcode" number="B" targetptr="errcode"><ttl>List of error codes</ttl><xreftext>Appendix B, <i>List of error codes</i></xreftext><obj element="term" href="#ER_NONMASTER" number="" targetptr="ER_NONMASTER"><ttl>???TITLE???</ttl><xreftext>ER_NONMASTER</xreftext></obj><obj element="term" href="#ER_ILLEGAL_PARAMS" number="" targetptr="ER_ILLEGAL_PARAMS"><ttl>???TITLE???</ttl><xreftext>ER_ILLEGAL_PARAMS</xreftext></obj><obj element="term" href="#ER_MEMORY_ISSUE" number="" targetptr="ER_MEMORY_ISSUE"><ttl>???TITLE???</ttl><xreftext>ER_MEMORY_ISSUE</xreftext></obj><obj element="term" href="#ER_WAL_IO" number="" targetptr="ER_WAL_IO"><ttl>???TITLE???</ttl><xreftext>ER_WAL_IO</xreftext></obj><obj element="term" href="#ER_KEY_PART_COUNT" number="" targetptr="ER_KEY_PART_COUNT"><ttl>???TITLE???</ttl><xreftext>ER_KEY_PART_COUNT</xreftext></obj><obj element="term" href="#ER_NO_SUCH_SPACE" number="" targetptr="ER_NO_SUCH_SPACE"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_SPACE</xreftext></obj><obj element="term" href="#ER_NO_SUCH_INDEX" number="" targetptr="ER_NO_SUCH_INDEX"><ttl>???TITLE???</ttl><xreftext>ER_NO_SUCH_INDEX</xreftext></obj><obj element="term" href="#ER_PROC_LUA" number="" targetptr="ER_PROC_LUA"><ttl>???TITLE???</ttl><xreftext>ER_PROC_LUA</xreftext></obj><obj element="term" href="#ER_FIBER_STACK" number="" targetptr="ER_FIBER_STACK"><ttl>???TITLE???</ttl><xreftext>ER_FIBER_STACK</xreftext></obj><obj element="term" href="#ER_UPDATE_FIELD" number="" targetptr="ER_UPDATE_FIELD"><ttl>???TITLE???</ttl><xreftext>ER_UPDATE_FIELD</xreftext></obj></div><div element="appendix" href="#limitations" number="C" targetptr="limitations"><ttl>Limitations</ttl><xreftext>Appendix C, <i>Limitations</i></xreftext><obj element="term" href="#limitations-index-field-count" number="" targetptr="limitations-index-field-count"><ttl>???TITLE???</ttl><xreftext>limitations-index-field-count</xreftext></obj><obj element="term" href="#limitations-index-count" number="" targetptr="limitations-index-count"><ttl>???TITLE???</ttl><xreftext>limitations-index-count</xreftext></obj><obj element="term" href="#limitations-tuple-field-count" number="" targetptr="limitations-tuple-field-count"><ttl>???TITLE???</ttl><xreftext>limitations-tuple-field-count</xreftext></obj><obj element="term" href="#limitations-space-count" number="" targetptr="limitations-space-count"><ttl>???TITLE???</ttl><xreftext>limitations-space-count</xreftext></obj><obj element="term" href="#limitations-connections-count" number="" targetptr="limitations-connections-count"><ttl>???TITLE???</ttl><xreftext>limitations-connections-count</xreftext></obj><obj element="term" href="#limitations-slab-alloc-arena-size" number="" targetptr="limitations-slab-alloc-arena-size"><ttl>???TITLE???</ttl><xreftext>limitations-slab-alloc-arena-size</xreftext></obj><obj element="term" href="#limitations-update-count" number="" targetptr="limitations-update-count"><ttl>???TITLE???</ttl><xreftext>limitations-updae-count</xreftext></obj></div><div element="appendix" href="#lua-tutorial" number="D" targetptr="lua-tutorial"><ttl>Lua tutorial</ttl><xreftext>Appendix D, <i>Lua tutorial</i></xreftext><div element="section" href="#lua-tutorial-insert" number="" targetptr="lua-tutorial-insert"><ttl>Insert one million tuples with a Lua stored procedure</ttl><xreftext>the section called “Insert one million tuples with a Lua stored procedureâ€</xreftext></div><div element="section" href="#lua-tutorial-sum" number="" targetptr="lua-tutorial-sum"><ttl>Sum a JSON field for all tuples</ttl><xreftext>the section called “Sum a JSON field for all tuplesâ€</xreftext></div></div><div element="appendix" href="#plugins" number="E" targetptr="plugins"><ttl>Plugins</ttl><xreftext>Appendix E, <i>Plugins</i></xreftext><obj element="para" href="#plugin-sql-dbms-plugins" number="" targetptr="plugin-sql-dbms-plugins"><ttl>???TITLE???</ttl><xreftext>Appendix E, <i>Plugins</i></xreftext></obj><obj element="para" href="#plugin-mysql-example" number="" targetptr="plugin-mysql-example"><ttl>???TITLE???</ttl><xreftext>Appendix E, <i>Plugins</i></xreftext></obj><obj element="para" href="#plugin-postgresql-example" number="" targetptr="plugin-postgresql-example"><ttl>???TITLE???</ttl><xreftext>Appendix E, <i>Plugins</i></xreftext></obj></div></div> diff --git a/doc/user/tnt-fo.xsl b/doc/user/tnt-fo.xsl deleted file mode 100644 index 1081c345ad4dd9fb94be512dc6b38b321633b2f8..0000000000000000000000000000000000000000 --- a/doc/user/tnt-fo.xsl +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version='1.0'?> -<xsl:stylesheet - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" - xmlns:xslthl="http://xslthl.sf.net"> - - <xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/fo/docbook.xsl"/> - - <xsl:param name="generate.toc" select="'book toc'"/> - <xsl:param name="fop1.extentions">1</xsl:param> - <xsl:param name="paper.type">A4</xsl:param> - <xsl:param name="highlight.source" select="1"/> - <xsl:param name="highlight.xslthl.config">file:////usr/share/xml/docbook/stylesheet/docbook-xsl-ns/highlighting/xslthl-config.xml</xsl:param> - - <xsl:param name="collect.xref.targets">all</xsl:param> -</xsl:stylesheet> diff --git a/doc/user/tnt-html-chunk.xsl b/doc/user/tnt-html-chunk.xsl deleted file mode 100644 index 248f83a463d90453c0dd8984506fdc8aa4a2a304..0000000000000000000000000000000000000000 --- a/doc/user/tnt-html-chunk.xsl +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version='1.0'?> - -<xsl:stylesheet - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" - xmlns:xslthl="http://xslthl.sf.net"> - <xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/html/chunk.xsl"/> - <xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/html/highlight.xsl"/> - <xsl:param name="highlight.source" select="1"/> - <xsl:param name="highlight.xslthl.config">file:////usr/share/xml/docbook/stylesheet/docbook-xsl-ns/highlighting/xslthl-config.xml</xsl:param> - <xsl:param name="use.id.as.filename" select="1"></xsl:param> - <xsl:param name="suppress.header.navigation" select="1"></xsl:param> - <xsl:param name="generate.toc"> - chapter toc - book toc - </xsl:param> - <xsl:param name="html.stylesheet" select="'/theme/docbook.css'"/> - <xsl:param name="collect.xref.targets">all</xsl:param> -</xsl:stylesheet> diff --git a/doc/user/tnt-html.xsl b/doc/user/tnt-html.xsl deleted file mode 100644 index c838f82390ab812f2cbeaca6af5e7d7c7ff64468..0000000000000000000000000000000000000000 --- a/doc/user/tnt-html.xsl +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version='1.0'?> -<xsl:stylesheet - xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" - xmlns:xslthl="http://xslthl.sf.net"> - <xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/html/docbook.xsl"/> - <xsl:import href="html-highlight.xsl"/> - <xsl:param name="collect.xref.targets">all</xsl:param> - <xsl:param name="generate.toc" select="'book toc'"/> - <xsl:param name="html.stylesheet" select="'/theme/docbook.css'"/> - <xsl:param name="highlight.source" select="1"/> - <xsl:param name="highlight.xslthl.config">file:////usr/share/xml/docbook/stylesheet/docbook-xsl-ns/highlighting/xslthl-config.xml</xsl:param> -</xsl:stylesheet> diff --git a/doc/user/triggers.xml b/doc/user/triggers.xml deleted file mode 100644 index 3bdfe3a1fce232351874f55398ab379b84a1851e..0000000000000000000000000000000000000000 --- a/doc/user/triggers.xml +++ /dev/null @@ -1,288 +0,0 @@ -<!DOCTYPE chapter [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:xi="http://www.w3.org/2001/XInclude" - xml:id="triggers"> -<title>Triggers</title> - - <para> - Triggers, also known as callbacks, are functions which the server executes - when certain events happen. Currently the two types of - triggers are <link linkend="sp-box-session-triggers">connection triggers</link>, - which are executed when a session begins or ends, - and <link linkend="sp-box-replace-triggers">replace</link> triggers - which are for database events, - </para> - - <para> - All triggers have the following characteristics. - - <itemizedlist mark='bullet'> - - <listitem> - <para> - They associate a <emphasis>function</emphasis> with an <emphasis>event</emphasis>. - The request to "define a trigger" consists of passing the name of the - trigger's function to one of the "on_<replaceable>event-name</replaceable>..." functions: - <code>on_connect()</code>, <code>on_disconnect()</code>, or <code>on_replace()</code>. - </para> - </listitem> - - <listitem> - <para> - They are <emphasis>defined by any user</emphasis>. - There are no privilege requirements for defining triggers. - </para> - </listitem> - - <listitem> - <para> - They are called <emphasis>after</emphasis> the event. - They are not called if the event ends prematurely due to an error. - </para> - </listitem> - - <listitem> - <para> - They are <emphasis>in server memory</emphasis>. - They are not stored in the database. - Triggers disappear when the server is shut down. - If there is a requirement to make them permanent, then - the function definitions and trigger settings should be - part of an initialization script. - </para> - </listitem> - - <listitem> - <para> - They have <emphasis>low overhead</emphasis>. - If a trigger is not defined, then the overhead is - minimal: merely a pointer dereference and check. - If a trigger is defined, then its overhead is equivalent to the - overhead of calling a stored procedure. - </para> - </listitem> - - <listitem> - <para> - They can be <emphasis>multiple</emphasis> for one event. - Triggers are executed in the reverse order that they were defined in. - </para> - </listitem> - - <listitem> - <para> - They must work <emphasis>within the event context</emphasis>. - If the function contains requests which normally could not occur - immediately after the event but before the return from the event, - effects are undefined. For example, defining a trigger function - as <code>os.exit()</code> or <code>box.rollback()</code> would - be bringing in requests outside the event context. - </para> - </listitem> - - <listitem> - <para> - They are <emphasis>replaceable</emphasis>. - The request to "redefine a trigger" consists of passing the - names of a new trigger function and an old trigger function - to one of the "on_<replaceable>event-name</replaceable>..." functions. - </para> - </listitem> - - </itemizedlist> - - </para> - -<section xml:id="sp-box-session-triggers" xreflabel="session triggers"> - <title>Connection triggers</title> -<variablelist> - <varlistentry> - <term> - <emphasis role="lua">box.session.on_connect(<replaceable>trigger-function-name</replaceable> [, <replaceable>old-trigger-function-name</replaceable>])</emphasis> - </term> - <listitem><para> - Define a trigger for execution when a new session is created due to - an event such as <ulink url="/doc/reference/console.html#console.connect"><code>console.connect()</code></ulink>. - The trigger function will be the first - thing executed after a new session is created. - If the trigger fails by raising an error, the error - is sent to the client and the connection is closed. - </para> - <para> - Parameters: trigger-function-name = name of a function which will become the trigger function; - (optional) old-trigger-function-name = name of an existing trigger function which will be - replaced by trigger-function-name. - If the parameters are (nil, old-trigger-function-name), then the old trigger is deleted. - </para> - <para> - Returns: nil. - </para> - <para> - Example: <code>function f () x = x + 1 end; box.session.on_connect(f)</code> - </para> - <warning> - <para> - If a trigger always results in an error, it may become - impossible to connect to the server to reset it. - </para> - </warning> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.session.on_disconnect(<replaceable>trigger-function-name</replaceable> [, <replaceable>old-trigger-function-name</replaceable>])</emphasis> - </term> - <listitem> - <para>Define a trigger for execution after a client has - disconnected. If - the trigger function causes an error, the error is logged but otherwise - is ignored. The trigger is invoked while the session associated - with the client still exists and can access session properties, - such as box.session.id. - </para> - <para> - Parameters: trigger-function-name = name of a function which will become the trigger function; - (optional) old-trigger-function-name = name of an existing trigger function which will be - replaced by trigger-function-name. - If the parameters are (nil, old-trigger-function-name), then the old trigger is deleted. - </para> - <para> - Returns: nil. - </para> - <para> - Example: <code>function f () x = x + 1 end; box.session.on_disconnect(f)</code> - </para> - </listitem> - </varlistentry> -</variablelist> - - <para> - <bridgehead renderas="sect4">Example</bridgehead> - After the following series of requests, the server - will write a message using the <ulink url="/doc/reference/log.html">log package</ulink> - whenever any user connects or disconnects. -<programlisting> -console = require('console'); console.delimiter('!') --this means ignore line feeds until next '!' -function log_connect () - local log - local m - log = require('log') - m = 'Connection. user=' .. box.session.user() .. ' id=' .. box.session.id() - log.info(m) - end! -function log_disconnect () - local log - local m - log = require('log') - m = 'Disconnection. user=' .. box.session.user() .. ' id=' .. box.session.id() - log.info(m) - end! -console.delimiter('')! -box.session.on_connect(log_connect) -box.session.on_disconnect(log_disconnect) -</programlisting> -Here is what might appear in the log file in a typical installation: -<programlisting> -2014-12-15 13:21:34.444 [11360] main/103/iproto I> - Connection. user=guest id=3 -2014-12-15 13:22:19.289 [11360] main/103/iproto I> - Disconnection. user=guest id=3 -</programlisting> - </para> - -</section> - - <section xml:id="sp-box-replace-triggers" xreflabel="replace triggers"> - <title>Replace triggers</title> -<variablelist> - - <varlistentry> - <term xml:id="on_replace"> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:on_replace(<replaceable>trigger-function-name</replaceable> [, <replaceable>old-trigger-function-name</replaceable>])</emphasis> - </term> - <listitem> - <para> - Create a "replace trigger". The <code>function-name</code> will be executed whenever a replace() or insert() - or update() or delete() happens to a tuple in <code>space-name</code>. - </para> - <para> - Parameters: trigger-function-name = name of a function which will become the trigger function; - (optional) old-trigger-function-name = name of an existing trigger function which will be - replaced by trigger-function-name. - If the parameters are (nil, old-trigger-function-name), then the old trigger is deleted. - </para> - <para> - Returns: nil. - </para> - <para> - Example: <code>function f () x = x + 1 end; box.space.X:on_replace(f)</code> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="run_triggers"> - <emphasis role="lua">box.space.<replaceable>space-name</replaceable>:run_triggers(<replaceable>true|false</replaceable>)</emphasis> - </term> - <listitem> - <para> - At the time that a trigger is defined, it is automatically enabled -- that is, it will be executed. - Replace triggers can be disabled with <code>box.space.<replaceable>space-name</replaceable>:run_triggers(false)</code> - and re-enabled with <code>box.space.<replaceable>space-name</replaceable>:run_triggers(true)</code>. - </para> - <para> - Returns: nil. - </para> - <para> - Example: <code>box.space.X:run_triggers(false)</code> - </para> - </listitem> - </varlistentry> - -</variablelist> - - <para> - <bridgehead renderas="sect4">Example</bridgehead> - The following series of requests will create a space, create an index, - create a function which increments a counter, create a trigger, - do two inserts, drop the space, and display the counter value -- which is 2, - because the function is executed once after each insert. -<programlisting>s = box.schema.space.create('space53') -s:create_index('primary', {parts = {1, 'NUM'}}) -function replace_trigger() replace_counter = replace_counter + 1 end -s:on_replace(replace_trigger) -replace_counter = 0 -t = s:insert{1, 'First replace'} -t = s:insert{2, 'Second replace'} -s:drop() -replace_counter</programlisting> - </para> - - <para> - <bridgehead renderas="sect4">Another Example</bridgehead> - The following series of requests will associate an existing - function named F with an existing space named T, - associate the function a second time with the same space - (so it will be called twice), disable all triggers of - T, and destroy each trigger by replacing with nil. -<programlisting>box.space.T:on_replace(F) -box.space.T:on_replace(F) -box.space.T:run_triggers(false) -box.space.T:on_replace(nil, F) -box.space.T:on_replace(nil, F)</programlisting> - </para> - - -</section> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/tutorial.xml b/doc/user/tutorial.xml deleted file mode 100644 index a4bc5e15ca797eecbffe043b677dcc7592e98084..0000000000000000000000000000000000000000 --- a/doc/user/tutorial.xml +++ /dev/null @@ -1,441 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="getting-started"> - -<title>Getting started</title> - -<para> -This chapter shows how to download, how to install, and how to start Tarantool for the first time. -</para> - -<para> -For production, if possible, you should download a binary (executable) package. -This will ensure that you have the same build of the same version that the developers have. -That makes analysis easier if later you need to -report a problem, and avoids subtle problems that might happen if -you used different tools or different parameters when building from source. -The section about binaries is <olink -targetptr="getting-started-binary"><quote>Downloading and -installing a binary package</quote></olink>. -</para> - -<para> -For development, you will want to download a source package and make the binary -by yourself using a C/C++ compiler and common tools. -Although this is a bit harder, it gives more control. -And the source packages include additional files, for example the Tarantool test suite. -The section about source is -<link xlink:href="http://tarantool.org/doc/dev_guide/building_from_source.html"><quote>Building from source</quote></link> -</para> - -<para> -If the installation has already been done, then you should try it out. - So we've provided some instructions that you can use to make a temporary <quote>sandbox</quote>. -In a few minutes you can start the server and type in some -database-manipulation statements. -The section about sandbox is <olink -targetptr="getting-started-start-stop"><quote>Starting Tarantool and making your first database</quote></olink>. -</para> - -<section xml:id="getting-started-binary"> -<title>Downloading and installing a binary package</title> - -<para> -The repositories for the <quote>stable</quote> release are at <link xlink:href="http://tarantool.org/dist/stable" xlink:title="tarantool.org/dist/stble">tarantool.org/dist/stable</link>. -The repositories for the <quote>master</quote> release are at <link xlink:href="http://tarantool.org/dist/master" xlink:title="tarantool.org/dist/master">tarantool.org/dist/master</link>. -Since this is the manual for the <quote>master</quote> release, all instructions use <link xlink:href="http://tarantool.org/dist/master" xlink:title="tarantool.org/dist/master">tarantool.org/dist/master</link>. -</para> - -<para> -An automatic build system creates, tests and publishes packages for every push into the master branch. -Therefore if you looked at <link xlink:href="http://tarantool.org/dist/master" xlink:title="tarantool.org/dist/master">tarantool.org/dist/master</link> you would see -that there are source files and subdirectories for the packages that will be described in this section. -</para> - -<para> -To download and install the package that's appropriate for your environment, -start a shell (terminal) and enter one of the following sets of command-line instructions. -</para> -<para> -More advice for binary downloads is at <link xlink:href="http://tarantool.org/download.html">http://tarantool.org/download.html</link>. -</para> - - -<simplesect> -<title>Debian GNU/Linux</title> -<para> -There is always an up-to-date Debian repository at -<link xlink:href="http://tarantool.org/dist/master/debian">http://tarantool.org/dist/master/debian</link> -The repository contains builds for Debian unstable "Sid", stable "Wheezy", -forthcoming "Jessie". Add the tarantool.org repository to your apt -sources list. $release is an environment variable which will -contain the Debian version code e.g. "Wheezy": -<programlisting> -<userinput> -<command>wget</command> http://tarantool.org/dist/public.key -<command>sudo apt-key add</command> <filename>./public.key</filename> -release=`lsb_release -c -s` -# append two lines to a list of source repositories -<command>echo</command> "deb http://tarantool.org/dist/master/debian/ $release main" | \ -<command>sudo tee</command> <option>-a</option> <filename>/etc/apt/sources.list.d/tarantool.list</filename> -<command>echo</command> "deb-src http://tarantool.org/dist/master/debian/ $release main" | \ -<command>sudo tee</command> <option>-a</option> <filename>/etc/apt/sources.list.d/tarantool.list</filename> -# install -<command>sudo apt-get update</command> -<command>sudo apt-get install</command> tarantool -</userinput> -</programlisting> -</para> -</simplesect> - -<simplesect> -<title>Ubuntu</title> -<para> -There is always an up-to-date Ubuntu repository at -<link xlink:href="http://tarantool.org/dist/master/ubuntu">http://tarantool.org/dist/master/ubuntu</link> -The repository contains builds for Ubuntu 12.04 "precise", -13.10 "saucy", and 14.04 "trusty". -Add the tarantool.org repository to your apt sources list -$release is an environment variable which will contain the Ubuntu version -code e.g. "precise". If you want the version that comes with -Ubuntu, start with the lines that follow the '# install' comment: -<programlisting> -<userinput> -<command>cd</command> ~ -<command>wget</command> http://tarantool.org/dist/public.key -<command>sudo apt-key add</command> <filename>./public.key</filename> -release=`lsb_release -c -s` -# append two lines to a list of source repositories -<command>echo</command> "deb http://tarantool.org/dist/master/ubuntu/ $release main" | \ -<command>sudo tee</command> <option>-a</option> <filename>/etc/apt/sources.list.d/tarantool.list</filename> -<command>echo</command> "deb-src http://tarantool.org/dist/master/ubuntu/ $release main" | \ -<command>sudo tee</command> <option>-a</option> <filename>/etc/apt/sources.list.d/tarantool.list</filename> -# install -<command>sudo apt-get update</command> -<command>sudo apt-get install</command> tarantool -</userinput> -</programlisting> -</para> -</simplesect> - -<simplesect> -<title>CentOS</title> -<para> -These instructions are applicable for CentOS version 5 or 6, -and RHEL version 5 or 6. -Pick the CentOS repository which fits your CentOS/RHEL version -and your x86 platform: -<itemizedlist> -<listitem><simpara> -<link xlink:href="http://tarantool.org/dist/master/centos/5/os/i386">http://tarantool.org/dist/master/centos/5/os/i386</link> for version 5, x86-32 -</simpara></listitem> -<listitem><simpara> -<link xlink:href="http://tarantool.org/dist/master/centos/6/os/i386">http://tarantool.org/dist/master/centos/6/os/i386</link> for version 6, x86-32 -</simpara></listitem> -<listitem><simpara> -<link xlink:href="http://tarantool.org/dist/master/centos/5/os/x86_64">http://tarantool.org/dist/master/centos/5/os/x86_64</link> for version 5, x86-64 -</simpara></listitem> -<listitem><simpara> -<link xlink:href="http://tarantool.org/dist/master/centos/6/os/x86_64">http://tarantool.org/dist/master/centos/6/os/x86_64</link> for version 6, x86-64 -</simpara></listitem> -</itemizedlist> -Add the following section to your yum repository list -(<filename>/etc/yum.repos.d/tarantool.repo</filename>) -(in the following instructions, $releasever i.e. CentOS release -version must be either 5 or 6 and $basearch i.e. base -architecture must be either i386 or x86_64): -<programlisting> -<userinput> -# [tarantool] -name=CentOS-<replaceable>$releasever</replaceable> - Tarantool -baseurl=http://tarantool.org/dist/master/centos/<replaceable>$releasever</replaceable>/os/<replaceable>$basearch</replaceable>/ -enabled=1 -gpgcheck=0 -</userinput></programlisting> -For example, if you have CentOS version 6 and x86-64, you can -add the new section thus: -<programlisting><userinput> -<command>echo</command> "[tarantool]" | \ -<command>sudo tee</command> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "name=CentOS-6 - Tarantool"| <command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "baseurl=http://tarantool.org/dist/master/centos/6/os/x86_64/" | \ -<command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "enabled=1" | <command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "gpgcheck=0" | <command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename> -</userinput> -</programlisting> -</para> -</simplesect> - -<simplesect> -<title>Fedora</title> -<para> -These instructions are applicable for Fedora 19 or Fedora 20. -Pick the Fedora repository, for example <link xlink:href="http://tarantool.org/dist/master/fedora/20/x86_64">http://tarantool.org/dist/master/fedora/20/x86_64</link> for version 20, x86-64. -Add the following section to your yum repository list -(<filename>/etc/yum.repos.d/tarantool.repo</filename>) -(in the following instructions, $releasever i.e. Fedora release -version must be 19 or 20 and $basearch i.e. base architecture must be x86_64): -<programlisting> -<userinput> -[tarantool] -name=Fedora-<replaceable>$releasever</replaceable> - Tarantool -baseurl=http://tarantool.org/dist/master/fedora/<replaceable>$releasever</replaceable><replaceable>$basearch</replaceable>/ -enabled=1 -gpgcheck=0 -</userinput> -</programlisting> -For example, if you have Fedora version 20, you can add the new section thus: -<programlisting> -<userinput> -<command>echo</command> "[tarantool]" | \ -<command>sudo tee</command> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "name=Fedora-20 - Tarantool"| <command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "baseurl=http://tarantool.org/dist/master/fedora/20/x86_64/" | \ -<command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "enabled=1" | <command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename> -<command>echo</command> "gpgcheck=0" | <command>sudo tee</command> <option>-a</option> <filename>/etc/yum.repos.d/tarantool.repo</filename></userinput></programlisting> -Then install with <code>sudo yum install tarantool</code>. -</para> -</simplesect> - -<simplesect> -<title>Gentoo</title> -<para> -Tarantool is available from tarantool portage overlay. -Use layman to add the overlay to your system: -<programlisting> -<userinput> -<command>layman</command> <option>-S</option> -<command>layman</command> <option>-a</option> tarantool -<command>emerge</command> <filename>dev-db/tarantool</filename> <option>-av</option> -</userinput> -</programlisting> -</para> -</simplesect> - -<simplesect> -<title>FreeBSD</title> -<para> -With your browser go to the FreeBSD ports page -<link xlink:href="http://www.freebsd.org/ports/index.html">http://www.freebsd.org/ports/index.html</link>. -Enter the search term: tarantool. -Choose the package you want. -</para> - -</simplesect> -<simplesect> -<title>Mac OS X</title> -<para> -This is actually a <quote><productname>homebrew</productname></quote> recipe -so it's not a true binary download, some source code is involved. -First upgrade Clang (the C compiler) to version 3.2 or later using -Command Line Tools for Xcode disk image version 4.6+ from -Apple Developer web-site. Then download the recipe file from -<link xlink:href="http://tarantool.org/dist/master/tarantool.rb">tarantool.org/dist/master/tarantool.rb</link>. -Make the file executable, execute it, and the script in the file should -handle the necessary steps with cmake, make, and make install. -</para> -</simplesect> - -</section> - -<section xml:id="getting-started-start-stop"> -<title>Starting Tarantool and making your first database</title> - -<para> -Here is how to create a simple test database after installing. -</para> - -<para> -1. Create a new directory. It's just for tests, you can delete it when the tests are over.<programlisting><userinput> -<command>mkdir</command> <replaceable>~/tarantool_sandbox</replaceable> -<command>cd</command> <replaceable>~/tarantool_sandbox</replaceable> </userinput></programlisting> -</para> - -<para> -2. Start the server. -The server name is <computeroutput><filename>tarantool</filename></computeroutput>.<programlisting><userinput> -#if you downloaded a binary with apt-get or yum, say this: - <command>/usr/bin/tarantool</command> -#if you downloaded and untarred a binary tarball to ~/tarantool, say this: - <command>~/tarantool/bin/tarantool</command> -#if you built from a source download, say this: - <command>~/tarantool/src/tarantool</command> </userinput></programlisting> -</para> - -<para> - The server starts in interactive mode and outputs a command prompt. - To turn on the database, <link linkend="configuration-parameters">configure it</link>: -<programlisting><prompt>tarantool></prompt> <userinput>box.cfg{listen=3301}</userinput></programlisting> - (this minimal example is sufficient). -</para> - -<para> -If all goes well, you will see the server displaying progress as it initializes, something like this:<programlisting><computeroutput> -tarantool> box.cfg{listen=3301} -2014-08-07 09:41:41.077 ... version 1.6.3-439-g7e1011b -2014-08-07 09:41:41.077 ... log level 5 -2014-08-07 09:41:41.078 ... mapping 1073741824 bytes for a shared arena... -2014-08-07 09:41:41.079 ... initialized -2014-08-07 09:41:41.081 ... initializing an empty data directory -2014-08-07 09:41:41.095 ... creating `./00000000000000000000.snap.inprogress' -2014-08-07 09:41:41.095 ... saving snapshot `./00000000000000000000.snap.inprogress' -2014-08-07 09:41:41.127 ... done -2014-08-07 09:41:41.128 ... primary: bound to 0.0.0.0:3301 -2014-08-07 09:41:41.128 ... ready to accept requests</computeroutput></programlisting> -</para> - -<para> - Now that the server is up, you could start up a different shell and - connect to its primary port with<programlisting> - <command>telnet 0 3301</command></programlisting> -but for example purposes it is simpler to just leave the -server running in "interactive mode". -On production machines the interactive mode is just -for administrators, but because it's convenient for -learning it will be used for most examples in this manual. - -Tarantool is waiting for the user to type instructions. -</para> - -<para> -To create the first space and the first <link linkend="an-index">index</link>, try this:<programlisting> -<prompt>tarantool> </prompt><userinput>s = box.schema.space.create('tester')</userinput> -<prompt>tarantool> </prompt><userinput>i = s:create_index('primary', {type = 'hash', parts = {1, 'NUM'}})</userinput></programlisting> -</para> - -<para> -To insert three <quote>tuples</quote> (our name for <quote>records</quote>) into the first <quote>space</quote> of the database -try this:<programlisting><prompt>tarantool> </prompt><userinput>t = s:insert({1})</userinput> -<prompt>tarantool> </prompt><userinput>t = s:insert({2, 'Music'})</userinput> -<prompt>tarantool> </prompt><userinput>t = s:insert({3, 'Length', 93})</userinput> -</programlisting> - -To select a tuple from the first space of the database, -using the first defined key, try this:<programlisting><prompt>tarantool> </prompt><userinput>s:select{3}</userinput></programlisting> - -Your terminal screen should now look like this:<programlisting><computeroutput> -tarantool> s = box.schema.space.create('tester') -2014-06-10 12:04:18.158 ... creating `./00000000000000000002.xlog.inprogress' ---- -... -tarantool> s:create_index('primary', {type = 'hash', parts = {1, 'NUM'}}) ---- -... -tarantool> t = s:insert{1} ---- -... -tarantool> t = s:insert{2, 'Music'} ---- -... -tarantool> t = s:insert{3, 'Length', 93} ---- -... -tarantool> s:select{3} ---- -- - [3, 'Length', 93] -... - -tarantool></computeroutput></programlisting> -</para> - -<para> -Now, to prepare for the example in the next section, -try this:<programlisting><prompt>tarantool> </prompt><userinput>box.schema.user.grant('guest','read,write,execute','universe')</userinput></programlisting> -</para> - -</section> -<section xml:id="getting-started-connecting-remotely"> -<title>Starting another Tarantool instance and connecting remotely</title> - -<para> -In the previous section the first request was -with "box.cfg{listen=3301}". The "listen" value can be -any form of URI (uniform resource identifier); in this -case it's just a local port: port 3301. It's possible -to send requests to the listen URI via (a) telnet, -(b) a connector (which will be the subject of Chapter 8), or -(c) another instance of Tarantool. Let's try (c). -</para> -<para> -1. Switch to another terminal. On Linux, for example, this -means starting another instance of a Bash shell. -There is no need to use <computeroutput><command>cd</command></computeroutput> to switch to the ~/tarantool_sandbox directory. -</para> -<para> -2. Start the second instance of Tarantool. -The server name is <computeroutput><filename>tarantool</filename></computeroutput>.<programlisting><userinput> -#if you downloaded a binary with apt-get or yum, say this: - <command>/usr/bin/tarantool</command> -#if you downloaded and untarred a binary tarball to ~/tarantool, say this: - <command>~/tarantool/bin/tarantool</command> -#if you built from a source download, say this: - <command>~/tarantool/src/tarantool</command> </userinput></programlisting> -</para> -<para> -3. Try these requests:<programlisting><userinput>console = require('console') -console.connect('localhost:3301') -box.space.tester:select{2}</userinput></programlisting> -</para> -<para> -The requests are saying "use the <ulink url="/doc/reference/console.html">console package</ulink> to connect to the -Tarantool server that's listening on localhost:3301, send a request -to that server, and display the result." The result in this case is one of -the tuples that was inserted earlier. -Your terminal screen should now look like this:<programlisting><computeroutput> -... - -tarantool> console = require('console') ---- -... - -tarantool> console.connect('localhost:3301') -2014-08-31 12:46:54.650 [32628] main/101/interactive I> connected to localhost:3301 ---- -... - -localhost:3301> box.space.tester:select{2} ---- -- - [2, 'Music'] -... - -localhost:3301></computeroutput></programlisting> -</para> - -<para> -You can repeat box.space...:insert{} and box.space...:select{} indefinitely, -on either Tarantool instance. -When the testing is over: -To drop the space: <computeroutput>s:drop()</computeroutput>. -To stop tarantool: <keycombo><keysym>Ctrl</keysym><keysym>C</keysym></keycombo>. -To stop tarantool (an alternative): <computeroutput>os.exit()</computeroutput>. -To stop tarantool (from another terminal): <computeroutput><command>sudo pkill</command> -f tarantool</computeroutput>. -To destroy the test: <computeroutput><command>rm</command> -r ~/tarantool_sandbox</computeroutput>. -</para> - -<sidebar> -<para> -To review ... -If you followed all the instructions in this chapter, then -so far you have: installed Tarantool from either a binary -or a source repository, started up the Tarantool server, -inserted and selected tuples. -</para> -</sidebar> - -</section> - - - - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/user.xml b/doc/user/user.xml deleted file mode 100644 index fcc312910291cd1d517479676d47ff7253f1ef0f..0000000000000000000000000000000000000000 --- a/doc/user/user.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<book xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xi="http://www.w3.org/2001/XInclude" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="tarantool-user-guide"> -<title>Tarantool User Guide, version &tnt_version;</title> -<xi:include href="preface.xml"/> -<xi:include href="tutorial.xml"/> -<xi:include href="databases.xml"/> -<xi:include href="triggers.xml"/> -<xi:include href="replication.xml"/> -<xi:include href="server-administration.xml"/> -<xi:include href="configuration-reference.xml"/> -<xi:include href="connectors.xml"/> -<xi:include href="errcode.xml"/> -<xi:include href="proctitle.xml"/> -<xi:include href="lua-tutorial.xml"/> -<xi:include href="plugins.xml"/> -<!-- -<xi:include href="faq.xml"/> ---> -</book> -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/www/CMakeLists.txt b/doc/www/CMakeLists.txt index 4d1945c0e2911236746f7a07840de3dc4040ba3d..2f1a54930de67f204442d0b0a723c59d6950be15 100644 --- a/doc/www/CMakeLists.txt +++ b/doc/www/CMakeLists.txt @@ -5,5 +5,4 @@ if (PELICAN STREQUAL "PELICAN-NOTFOUND") endif() add_custom_target(www ALL - DEPENDS html-saxon html-saxon-chunk COMMAND ${PELICAN} -v) diff --git a/doc/www/pelicanconf.py b/doc/www/pelicanconf.py index 7bb7b92a3ec3e17af5410ee8e0712424cc732b1f..6048301885249f998ebba48bafe5b169ad288da6 100644 --- a/doc/www/pelicanconf.py +++ b/doc/www/pelicanconf.py @@ -14,7 +14,7 @@ TIMEZONE = 'Europe/Moscow' DEFAULT_LANG = u'en' -PLUGINS = ['plugins.documentation', 'plugins.beautifulsite'] +PLUGINS = ['plugins.beautifulsite'] # Feed generation is usually not desired when developing FEED_ALL_ATOM = None @@ -23,7 +23,6 @@ TRANSLATION_FEED_ATOM = None DEFAULT_PAGINATION = False -DOCS_PATH = ['doc'] BSITE_PATH = ['newsite'] ARTICLE_EXCLUDES = ['doc', 'newsite'] diff --git a/doc/www/plugins/documentation/__init__.py b/doc/www/plugins/documentation/__init__.py deleted file mode 100644 index e77810ed33ed27b0cfc67a381a7fc252aeca4964..0000000000000000000000000000000000000000 --- a/doc/www/plugins/documentation/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .documentation import * diff --git a/doc/www/plugins/documentation/documentation.py b/doc/www/plugins/documentation/documentation.py deleted file mode 100644 index d2013af2b00da6a8b0f9a961ae69ee41a7005919..0000000000000000000000000000000000000000 --- a/doc/www/plugins/documentation/documentation.py +++ /dev/null @@ -1,121 +0,0 @@ -from pelican import signals -from pelican.generators import Generator -from pelican.contents import Content, is_valid_content - -import os -import glob -import logging -import itertools - -from BeautifulSoup import BeautifulSoup as BSHTML - -logger = logging.getLogger(__name__) - -class Documentation(Content): - mandatory_properties = ('title', ) - default_template = 'old_documentation' - -class DocumentationContainer(object): - def __init__(self, opage): - self.opage = opage - self.mpage = [] - - def add_mpage(self, mpage): - self.mpage.append(mpage) - -class DocumentationGenerator(Generator): - def __init__(self, *args, **kwargs): - super(DocumentationGenerator, self).__init__(*args, **kwargs) - self.doc_html = [] - self.doc_rst = [] - - def _doc_read_file(self, relpath, op=False): - abspath = os.path.join(self.path, relpath) - page = open(abspath, 'r').read() - page = type('Documentation', (object, ), { - 'get_relative_source_path': (lambda x: x.save_as), - 'content' : page, - 'title' : BSHTML(page).find('title').getText(), - 'url' : relpath if op else os.path.dirname(relpath), - 'save_as' : relpath, - 'template': 'old_documentation' - })() - self.add_source_path(page) - return page - - def generate_context(self): - def b_path(left, right): - return os.path.join(left, - os.path.basename(right)) - def db_path(left, right): - return os.path.join(left, - os.path.basename(os.path.dirname(right)), - os.path.basename(right)) - - for docpath in self.settings['DOCS_PATH']: - abspath = os.path.join(self.path, docpath, '*.html') - for op_abspath in glob.glob(abspath): - op_relpath = b_path(docpath, op_abspath) - if not os.path.isfile(op_abspath): - continue - page = self._doc_read_file(op_relpath, True) - self.doc_html.append(DocumentationContainer(page)) - if not os.path.isdir(op_abspath[:-5]): - continue - mp_abspath = os.path.join(op_abspath[:-5], '*.html') - for mp_html_abspath in glob.glob(mp_abspath): - mp_html_relpath = db_path(docpath, mp_html_abspath) - if not os.path.isfile(mp_html_abspath): - continue - page = self._doc_read_file(mp_html_relpath, False) - self.doc_html[-1].add_mpage(page) - for docpath in self.settings['DOCS_PATH']: - abspath = os.path.join(self.path, docpath, '*.rst') - for op_abspath in glob.glob(abspath): - op_relpath = b_path(docpath, op_abspath) - if not os.path.isfile(op_abspath): - continue - page = None - try: - page = self.readers.read_file( - base_path = self.path, path = op_relpath, - content_class = Documentation, context = self.context) - except Exception as e: - logger.error('Could not process %s\n%s', op_relpath, e, - exc_info=self.settings.get('DEBUG', False)) - continue - if not is_valid_content(page, op_relpath): - continue - if page: - self.doc_rst.append(DocumentationContainer(page)) - - def generate_output(self, writer): - for doc_cont in self.doc_html: - opage = doc_cont.opage - writer.write_file( - opage.save_as, - self.get_template(opage.template), - self.context, - page = opage, - documentation = True) - for mpage in doc_cont.mpage: - writer.write_file( - mpage.save_as, - self.get_template(mpage.template), - self.context, - page = mpage, - documentation = True) - for doc_cont in self.doc_rst: - opage = doc_cont.opage - writer.write_file( - opage.save_as, - self.get_template(opage.template), - self.context, - page = opage, - documentation = False) - -def get_generators(pelican_object): - return DocumentationGenerator - -def register(): - signals.get_generators.connect(get_generators)