diff --git a/doc/sphinx/.gitignore b/doc/sphinx/.gitignore index f935021a8f8a7bd22f9d6703cafa5134bb6a57f8..7705395c26abd9044835278630dc14086fe4aee3 100644 --- a/doc/sphinx/.gitignore +++ b/doc/sphinx/.gitignore @@ -1 +1,2 @@ !.gitignore +*.pyc diff --git a/doc/sphinx/_static/headers.js b/doc/sphinx/_static/headers.js new file mode 100644 index 0000000000000000000000000000000000000000..ac5cd6a0f63ebe0cacb6724ae3605c2ca12be20d --- /dev/null +++ b/doc/sphinx/_static/headers.js @@ -0,0 +1,29 @@ +$(document).ready(function () { + $("div>h1").remove(); + $("h2, h3, h4, h5, h6").each( + function(i, el) { + var icon = '<i class="fa fa-link"></i>'; + var hlink = $(el).find(".headerlink"); + var hlink_id = hlink.attr("href"); + if (typeof(hlink_id) != 'undefined') { + $(hlink).remove(); + $(el).prepend($("<a />").addClass("headerlink").attr("href", hlink_id).html(icon)); + } + } + ); + $(".admonition.note p.first.admonition-title").each( + function(i, el) { + var icon = '<i class="fa fa-comments-o"></i>'; + $(el).html(icon + $(el).html()); + } + ); + $(".admonition.warning p.first.admonition-title").each( + function(i, el) { + var icon = '<i class="fa fa-exclamation-triangle"></i>'; + $(el).html(icon + $(el).html()); + } + ); + +}); + +// vim: syntax=javascript ts=2 sts=2 sw=2 expandtab diff --git a/doc/sphinx/_static/sphinx_design.css b/doc/sphinx/_static/sphinx_design.css index 7b5a3782f7a92f71c722dc3924749b340f2f2fc6..e975b609f80fc946db9b82979438ad44b6236e62 100644 --- a/doc/sphinx/_static/sphinx_design.css +++ b/doc/sphinx/_static/sphinx_design.css @@ -250,10 +250,71 @@ tr.field td p { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAEAAAAAARAQMAAABnOfukAAAABlBMVEUAAAD19fWydBufAAAAAXRSTlMAQObYZgAAADZJREFUaN7t0gEBAAAIAiD/n7YBTRA2kO4InwDruiMIgAAIgAAIgAAIsK47ggAIgAAIgAAIwAHksoxHlAvP9AAAAABJRU5ErkJggg==') 50% -0px repeat-y; } +div.toctree-wrapper.compound { + padding: 20px 0px 0px 0px; +} + div.highlight { - overflow-x: scroll; + -webkit-border-radius: 7px; + -moz-border-radius: 7px; + border-radius: 7px; + overflow-x: auto; + margin: 5px 0px; + font-size: 13px; } -div.toctree-wrapper.compound { - padding: 20px 0px 0px 0px; +div.admonition { + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + padding: 10px; + margin: 5px 0; +} + +div.admonition.note { + background: rgb(223,223,223); +} + +div.admonition.warning { + background: rgb(255,228,228); +} + +p.admonition-title { + font-size: 16px; + font-weight: bold; +} + +p.admonition-title .fa { + margin: 0 10px 0 0; +} + +.descname { + font-weight: 600; +} + +dd table.field-list { + margin-top: 10px; +} + +td.field-body { + padding-left: 10px; + padding-bottom: 10px; +} + +th.field-name { + text-align: left; + font-weight: normal; +} + +table.docutils.field-list { + font-size: 13px; +} + +div.table tbody { + vertical-align: middle; + text-align: center; +} + +div.table td { + padding: 5px 15px; } diff --git a/doc/sphinx/_templates/base b/doc/sphinx/_templates/base index ffe2d44b79dd8ca96c78dcf65fc41abbb5741d89..2a596e512ca340bf948279673d83e63de161de4a 100644 --- a/doc/sphinx/_templates/base +++ b/doc/sphinx/_templates/base @@ -1,3 +1,4 @@ + {% import "menu" as menu %} {% include "custom_sphinx" with context %} @@ -7,7 +8,7 @@ <head> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <title>{{ title }}</title> + <title>{{ title | cleantitle }}</title> <link rel="shortcut icon" href="/theme/favicon.ico" /> <link rel="stylesheet" href="/theme/design.css" /> <link rel="stylesheet" href="/theme/pygmentize.css" /> diff --git a/doc/sphinx/_templates/layout.html b/doc/sphinx/_templates/layout.html index 9048d8dbf0ec42c996e80e9a607f6dc6a0471361..70168830a6eb8721de1078cbf978c4d40a1269e5 100644 --- a/doc/sphinx/_templates/layout.html +++ b/doc/sphinx/_templates/layout.html @@ -5,22 +5,7 @@ {% block header_scripts %} <link rel="stylesheet" href="/doc/_static/sphinx_design.css" /> <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"> - <script> - $(document).ready(function () { - $("div>h1").remove(); - $("h2, h3, h4, h5, h6").each( - function(i, el) { - var icon = '<i class="fa fa-link"></i>'; - var hlink = $(el).find(".headerlink"); - var hlink_id = hlink.attr("href"); - if (typeof(hlink_id) != 'undefined') { - $(hlink).remove(); - $(el).prepend($("<a />").addClass("headerlink").attr("href", hlink_id).html(icon)); - } - } - ) - }); - </script> + <script type="text/javascript" src="../_static/headers.js"></script> {{ super() }} {% endblock header_scripts %} diff --git a/doc/sphinx/conf.py b/doc/sphinx/conf.py index 9fd55ad303c839eff3175c622e5e81daaf597387..a7cf79d0601437496f34229d2afaa3a32372d31a 100644 --- a/doc/sphinx/conf.py +++ b/doc/sphinx/conf.py @@ -18,7 +18,7 @@ import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ @@ -28,10 +28,12 @@ import os # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. + extensions = [ 'sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', + 'ext.filters' ] # Add any paths that contain templates here, relative to this directory. diff --git a/doc/sphinx/ext/__init__.py b/doc/sphinx/ext/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/doc/sphinx/ext/filters.py b/doc/sphinx/ext/filters.py new file mode 100644 index 0000000000000000000000000000000000000000..97c0c73b21ecb5170aeb8c91e0d6e89852b18e81 --- /dev/null +++ b/doc/sphinx/ext/filters.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +""" + .ext.filters + ~~~~~~~~~~~~ +""" + +import xml.etree.ElementTree as ET + +def add_jinja_filters(app): + app.builder.templates.environment.filters['cleantitle'] = (lambda x: ''.join(ET.fromstring('<p>'+x+'</p>').itertext())) + +def setup(app): + ''' + Adds extra jinja filters. + ''' + app.connect("builder-inited", add_jinja_filters) + return {'version': '0.0.1', 'parallel_read_safe': True} diff --git a/doc/sphinx/index.rst b/doc/sphinx/index.rst index 70c4a127d0ab7dc2b038acefc6e1ef35be0829f2..057673e19de9bd71255b953ed05e8a1f41e223b7 100644 --- a/doc/sphinx/index.rst +++ b/doc/sphinx/index.rst @@ -7,6 +7,7 @@ :maxdepth: 1 intro.rst + faq.rst .. raw:: html @@ -19,5 +20,5 @@ .. toctree:: :maxdepth: 1 - faq.rst + reference/index.rst dev_guide/index.rst diff --git a/doc/sphinx/reference/box_session.rst b/doc/sphinx/reference/box_session.rst new file mode 100644 index 0000000000000000000000000000000000000000..e11522b0e480e19bbb295694da3e9f769559f6a0 --- /dev/null +++ b/doc/sphinx/reference/box_session.rst @@ -0,0 +1,75 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `box.session` +------------------------------------------------------------------------------- + +The ``box.session`` package allows querying the session state, writing to a +session-specific temporary Lua table, or setting up triggers which will fire +when a session starts or ends. A *session* is an object associated with each +client connection. + +.. module:: box.session + +.. function:: id() + + :return: the unique identifier (ID) for the current session. + The result can be 0 meaning there is no session. + :rtype: number + +.. function:: exists(id) + + :return: 1 if the session exists, 0 if the session does not exist. + :rtype: number + +.. function:: peer(id) + + :return: If the specified session exists, the host address and port of + the session peer, for example "127.0.0.1:55457". If the + specified session does not exist, "0.0.0.0:0". The command is + executed on the server, so the "local name" is the server's host + and administrative port, and the "peer name" is the client's host + and port. + :rtype: string + +.. data:: storage + + A Lua table that can hold arbitrary unordered session-specific + names and values, which will last until the session ends. + +================================================= + Example +================================================= + +.. code-block:: lua + + tarantool> box.session.peer(session.id()) + --- + - 127.0.0.1:45129 + ... + tarantool> box.session.storage.random_memorandum = "Don't forget the eggs." + --- + ... + tarantool> box.session.storage.radius_of_mars = 3396 + --- + ... + tarantool> m = '' + --- + ... + tarantool> for k, v in pairs(box.session.storage) do m=m..k..'='..v..' ' end + --- + ... + tarantool> m + --- + - 'radius_of_mars=3396 random_memorandum=Don''t forget the eggs. ' + ... + +See the section `Triggers on connect and disconnect`_ for instructions +about defining triggers for connect and disconnect events with +``box.session.on_connect()`` and ``box.session.on_disconnect()``. See +the section `Authentication and access control`_ for instructions about +``box.session`` functions that affect user identification and security. + +.. _Triggers on connect and disconnect: http://tarantool.org/doc/user_guide.html#sp-box-session-triggers +.. _Authentication and access control: http://tarantool.org/doc/user_guide.html#authentication diff --git a/doc/sphinx/reference/console.rst b/doc/sphinx/reference/console.rst new file mode 100644 index 0000000000000000000000000000000000000000..77b30efd4478df87b8cd9567008bafdb89b7b845 --- /dev/null +++ b/doc/sphinx/reference/console.rst @@ -0,0 +1,77 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `console` +------------------------------------------------------------------------------- + +The console package allows one Tarantool server to access another Tarantool +server, and allows one Tarantool server to start listening on an administrative +host/port. + +.. module:: console + +.. function:: connect(uri [, options]) + + Connect to the server at URI_, change the prompt from 'tarantool' to + 'host:port', and act henceforth as a client until the user ends the + session or types ``control-D``. + + The console.connect function allows one Tarantool server, in interactive + mode, to access another Tarantool server over a TCP connection. Subsequent + requests will appear to be handled locally, but in reality the requests + are being sent to the remote server and the local server is acting as a + client. Once connection is successful, the prompt will change and + subsequent requests are sent to, and executed on, the remote server. + Results are displayed on the local server. To return to local mode, + enter ``control-D``. + + There are no restrictions on the types of requests that can be entered, + except those which are due to privilege restrictions -- by default the + login to the remote server is done with user name = 'guest'. The remote + server could allow for this by granting at least one privilege: + ``box.schema.user.grant('guest','execute','universe')``. + + :param string uri: + :param table options: The options may be necessary if the Tarantool + server at host:port requires authentication. + In such a case the connection might look + something like: + ``console.connect('netbox:123@127.0.0.1'})`` + + :return: nil + :except: the connection will fail if the target Tarantool server + was not initiated with ``box.cfg{listen=...}``. + + .. code-block:: lua + + tarantool> console = require('console') + --- + ... + tarantool> console.connect('198.18.44.44:3301') + --- + ... + 198.18.44.44:3301> -- prompt is telling us that server is remote + +.. function:: listen(host, port) + + Listen on host:port. The primary way of listening for incoming requests + is via the host and port, or URI_, specified in ``box.cfg{listen=...}``. + The alternative way of listening is via the host and port, or URI, + specified in ``console.listen(...)``. This alternative way is called + "administrative" or simply "admin port". + The listening is usually over a local host with a Unix socket, + specified as host = 'unix/', port = 'path/to/something.sock'. + + :param string host: + :param number port: + + The "admin" address is the port or URI_ to listen on for administrative + connections. It has no default value, so it must be specified if + connections will occur via telnet. It is not used unless assigned a + value. The parameters may be expressed with URI_ = Universal Resource + Identifier format, for example "unix://unix_domain_socket", or as a + numeric TCP port. Connections are often made with telnet. + A typical port value is 3313. + +.. _URI: http://tarantool.org/doc/user_guide.html#URI diff --git a/doc/sphinx/reference/digest.rst b/doc/sphinx/reference/digest.rst new file mode 100644 index 0000000000000000000000000000000000000000..19a1907b06364cbe1372537243f88bd8476768ed --- /dev/null +++ b/doc/sphinx/reference/digest.rst @@ -0,0 +1,170 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `digest` +------------------------------------------------------------------------------- + +A "digest" is a value which is returned by a `Cryptographic hash function`_ applied +against a string. Tarantool supports five types of cryptographic hash functions +(MD4_, MD5_, SHA-0_, SHA-1_, SHA-2_) as well as a checksum function (CRC32_) and two +functions for base64_. The functions in digest are: + +.. module:: digest + +.. function:: crc32(string) + crc32_update(number, string) + + Returns 32-bit checksum made with CRC32. |br| + Returns update of a checksum calculated with CRC32. + + .. NOTE:: + + This function uses the `CRC-32C (Castagnoli)`_ polynomial + value: 0x11EDC6F41 / 4812730177. If it is necessary to be + compatible with other checksum functions in other + programming languages, ensure that the other functions use + the same polynomial value. |br| For example, in Python, + install the crcmod package and say: + + .. code-block:: python + + >>> import crcmod + >>> fun = crcmod.mkCrcFun('4812730177') + >>> fun('string') + 3304160206L + +.. _CRC-32C (Castagnoli): https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Standards_and_common_use + +.. function:: sha(string) + sha_hex(string) + + Returns 160-bit digest made with SHA-0. Not recommended. |br| + Returns hexadecimal of a digest calculated with sha. + +.. function:: sha1(string) + sha1_hex(string) + + Returns 160-bit digest made with SHA-1. |br| + Returns hexadecimal of a digest calculated with sha1. + +.. function:: sha224(string) + sha224_hex(string) + + Returns 224-bit digest made with SHA-2. |br| + Returns hexadecimal of a digest calculated with sha224. + +.. function:: sha256(string) + sha256_hex(string) + + Returns 256-bit digest made with SHA-2. |br| + Returns hexadecimal of a digest calculated with sha256. + +.. function:: sha384(string) + sha384_hex(string) + + Returns 384-bit digest made with SHA-2. |br| + Returns hexadecimal of a digest calculated with sha384. + +.. function:: sha512(string) + sha512_hex(string) + + Returns 512-bit digest made with SHA-2. |br| + Returns hexadecimal of a digest calculated with sha512. + +.. function:: md4(string) + md4_hex(string) + + Returns 128-bit digest made with MD4. |br| + Returns hexadecimal of a digest calculated with md4. + +.. function:: md5(string) + md5_hex(string) + + Returns 256-bit digest made with MD5. |br| + Returns hexadecimal of a digest calculated with md5. + +.. function:: base64_encode(string) + base64_decode(string) + + Returns base64 encoding from a regular string. |br| + Returns a regular string from a base64 encoding. + +.. function:: urandom(integer) + + Returns array of random bytes with length = integer. + +.. function:: guava(integer, integer) + + Returns a number made with consistent hash. + + .. NOTE:: + + This function uses the `Consistent Hashing`_ algorithm of + the Google guava library. The first parameter should be a + hash code; the second parameter should be the number of + buckets; the returned value will be an integer between 0 + and the number of buckets. For example, + + .. code-block:: lua + + localhost> digest.guava(10863919174838991, 11) + 8 + +================================================= + Example +================================================= + +In the following example, the user creates two functions, ``password_insert()`` +which inserts a SHA-1_ digest of the word "**^S^e^c^ret Wordpass**" into a tuple +set, and ``password_check()`` which requires input of a password. + +.. code-block:: lua + + localhost> digest = require('digest') + localhost> -- this means ignore line feeds until next '!' + localhost> console = require('console'); console.delimiter('!') + localhost> function password_insert() + -> box.space.tester:insert{12345, + -> digest.sha1('^S^e^c^ret Wordpass')} + -> return 'OK' + -> end! + --- + ... + localhost> function password_check(password) + -> local t + -> t=box.space.tester:select{12345} + -> if (digest.sha1(password)==t[2]) then + -> print('Password is valid') + -> else + -> print('Password is not valid') + -> end + -> end! + --- + ... + localhost> password_insert()! + Call OK, 1 rows affected + ['OK'] + localhost> -- back to normal: commands end with line feed! + localhost> console.delimiter('') + +If a later user calls the ``password_check()`` function and enters +the wrong password, the result is an error. + +.. code-block:: lua + + localhost> password_check ('Secret Password') + --- + Password is not valid + ... + +.. _MD4: https://en.wikipedia.org/wiki/Md4 +.. _MD5: https://en.wikipedia.org/wiki/Md5 +.. _SHA-0: https://en.wikipedia.org/wiki/Sha-0 +.. _SHA-1: https://en.wikipedia.org/wiki/Sha-1 +.. _SHA-2: https://en.wikipedia.org/wiki/Sha-2 +.. _CRC32: https://en.wikipedia.org/wiki/Cyclic_redundancy_check +.. _base64: https://en.wikipedia.org/wiki/Base64 +.. _Cryptographic hash function: https://en.wikipedia.org/wiki/Cryptographic_hash_function +.. _Consistent Hashing: https://en.wikipedia.org/wiki/Consistent_hashing +.. _CRC-32C (Castagnoli): https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Standards_and_common_use diff --git a/doc/sphinx/reference/expirationd.rst b/doc/sphinx/reference/expirationd.rst new file mode 100644 index 0000000000000000000000000000000000000000..141a55f08b963656d150bcd715bac363fcec6147 --- /dev/null +++ b/doc/sphinx/reference/expirationd.rst @@ -0,0 +1,108 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `expirationd` +------------------------------------------------------------------------------- + +For a commercial-grade example of a Lua rock that works with Tarantool, let us +look at expirationd, which Tarantool supplies on GitHub_ with an Artistic license. +The expirationd.lua program is lengthy (about 500 lines), so here we will only +highlight the matters that will be enhanced by studying the full source later. + +.. code-block:: lua + + task.worker_fiber = fiber.create(worker_loop, task) + log.info("expiration: task %q restarted", task.name) + ... + fiber.sleep(expirationd.constants.check_interval) + ... + +Whenever one hears "daemon" in Tarantool, one should suspect it's being done +with :doc:`fiber`. The program is making a fiber and turning control over to it so +it runs occasionally, goes to sleep, then comes back for more. + +.. code-block:: lua + + for _, tuple in scan_space.index[0]:pairs(nil, {iterator = box.index.ALL}) do + ... + if task.is_tuple_expired(task.args, tuple) then + task.expired_tuples_count = task.expired_tuples_count + 1 + task.process_expired_tuple(task.space_id, task.args, tuple) + ... + +The "for" instruction can be translated as "iterate through the index of the +space that is being scanned", and within it, if the tuple is "expired" (that +is, if the tuple has a timestamp field which is less than the current time), +process the tuple as an expired tuple. + +.. code-block:: lua + + -- put expired tuple in archive + local function put_tuple_to_archive(space_id, args, tuple) + -- delete expired tuple + box.space[space_id]:delete{tuple[1]} + local email = get_field(tuple, 2) + if args.archive_space_id ~= nil and email ~= nil then + box.space[args.archive_space_id]:replace{email, os.time()} + end + end + +Ultimately the tuple-expiry process leads to ``put_tuple_to_archive()`` +which does a "delete" of a tuple from its original space, and an "insert" +of the same tuple into another space. Tarantool's "replace" function is +the same as an "insert" function without an error message if a tuple with +the same content already exists in the target space. + +.. code-block:: lua + + function expirationd.do_test(space_id, archive_space_id) + ... + +At this point, if the above explanation is worthwhile, it's clear that +``expirationd.lua`` starts a background routine (fiber) which iterates through +all the tuples in a space, sleeps cooperatively so that other fibers can +operate at the same time, and - whenever it finds a tuple that has expired +- deletes it from this space and puts it in another space. Now the +"``do_test()``" function can be used to create some sample spaces, let the +daemon run for a while, and print results. + +For those who like to see things run, here are the exact steps to get +expirationd through the test. + +1. Get ``expirationd.lua``. There are standard ways - it is after all part + of a standard rock_ - but for this purpose just copy the contents of + expirationd.lua_ to a default directory. +2. Start the Tarantool server as described before. +3. Execute these requests: + +.. code-block:: lua + + box.cfg{} + a = box.schema.space.create('origin') + a:create_index('first', {type = 'tree', parts = {1, 'NUM'}}) + b = box.schema.space.create('archive') + b:create_index('first', {type = 'tree', parts = {1, 'STR'}}) + expd = require('expirationd') + expd._debug = true + expd.do_test('origin', 'archive') + os.exit() + +The database-specific requests (``cfg``, ``space.create``, ``create_index``) +should already be familiar. The key for getting the rock rolling is +``expd = require('expirationd')``. The "``require``" function is what reads in +the program; it will appear in many later examples in this manual, when it's +necessary to get a package that's not part of the Tarantool kernel. After the +Lua variable expd has been assigned the value of the expirationd package, it's +possible to invoke the package's ``do_test()`` function. + +After a while, when the task has had time to do its iterations through the spaces, +``do_test()`` will print out a report showing the tuples that were originally in +the original space, the tuples that have now been moved to the archive space, and +some statistics. Of course, expirationd can be customized to do different things +by passing different parameters, which will be evident after looking in more detail +at the source code. + +.. _expirationd.lua: https://github.com/tarantool/expirationd/blob/master/expirationd.lua +.. _rock: http://tarantool.org/doc/user_guide.html#rocks +.. _GitHub: https://github.com/tarantool/expirationd/blob/master/expirationd.lua diff --git a/doc/sphinx/reference/fiber-ipc.rst b/doc/sphinx/reference/fiber-ipc.rst new file mode 100644 index 0000000000000000000000000000000000000000..56b232e6f6bdbf1ef476ecf852c919a6f8ea941e --- /dev/null +++ b/doc/sphinx/reference/fiber-ipc.rst @@ -0,0 +1,177 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `fiber-ipc` +------------------------------------------------------------------------------- + +The ``fiber-ipc`` package allows sending and receiving messages between +different processes. The words "different processes" in this context +mean different connections, different sessions, or different fibers. + +Call ``fiber.channel()`` to allocate space and get a channel object, +which will be called channel for examples in this section. Call the +other ``fiber-ipc`` routines, via channel, to send messages, receive +messages, or check ipc status. Message exchange is synchronous. The +channel is garbage collected when no one is using it, as with any +other Lua object. Use object-oriented syntax, for example +``channel:put(message)`` rather than ``fiber.channel.put(message)``. + +.. module:: fiber + +.. function:: channel([capacity]) + + Create a new communication channel. + + :param int capacity: positive integer as great as the maximum number of + slots (spaces for get or put or broadcast messages) + that might be pending at any given time. + + :return: new channel. + :rtype: userdata + +.. class:: channel + + .. method:: put(message[, timeout]) + + Send a message using a channel. If the channel is full, + ``channel:put()`` blocks until there is a free slot in the channel. + + :param lua_object message: + :param timeout: + :return: If timeout is provided, and the channel doesn't become empty for + the duration of the timeout, ``channel:put()`` returns false. + Otherwise it returns true. + :rtype: boolean + + .. method:: close() + + Close the channel. All waiters in the channel will be woken up. + All following ``channel:put()`` or ``channel:get()`` operations will + return an error (``nil``). + + .. method:: get([timeout]) + + Fetch a message from a channel. If the channel is empty, + ``channel:get()`` blocks until there is a message. + + :param timeout: + :return: the value placed on the channel by an earlier + ``channel:put()`` or ``channel:broadcast()``. + :rtype: lua_object + + .. method:: broadcast(message) + + If the channel is empty, ``channel:broadcast()`` is equivalent to + ``channel:put()``. Otherwise, ``channel:broadcast()`` sends the + message to all readers of the channel. + + :param message: + + .. method:: is_empty() + + Check whether the specified channel is empty (has no messages). + + :return: true if the specified channel is empty + :rtype: boolean + + .. method:: count() + + Find out how many messages are on the channel. The answer is 0 if the channel is empty. + + :return: the number of messages. + :rtype: number + + .. method:: is_full() + + Check whether the specified channel is full. + + :return: true if the specified channel is full (has no room for a new message). + :rtype: boolean + + .. method:: has_readers() + + Check whether the specified channel is empty and has readers waiting for + a message (because they have issued ``channel:get()`` and then blocked). + + :return: true if blocked users are waiting. Otherwise false. + :rtype: boolean + + .. method:: has_writers() + + Check whether the specified channel is full and has writers waiting + (because they have issued ``channel:put()`` and then blocked due to lack of room). + + :return: true if blocked users are waiting. Otherwise false. + :rtype: boolean + + .. method:: is_closed() + + :return: true if the specified channel is already closed. Otherwise false. + :rtype: boolean + +================================================= + Example +================================================= + +.. code-block:: lua + + fiber = require('fiber') + channel = fiber.channel(10) + function consumer_fiber() + while true do + local task = channel:get() + ... + end + end + + function consumer2_fiber() + while true do + -- 10 seconds + local task = channel:get(10) + if task ~= nil then + ... + else + -- timeout + end + end + end + + function producer_fiber() + while true do + task = box.space...:select{...} + ... + if channel:is_empty() then + -- channel is empty + end + + if channel:is_full() then + -- channel is full + end + + ... + if channel:has_readers() then + -- there are some fibers + -- that are waiting for data + end + ... + + if channel:has_writers() then + -- there are some fibers + -- that are waiting for readers + end + channel:put(task) + end + end + + function producer2_fiber() + while true do + task = box.space...select{...} + -- 10 seconds + if channel:put(task, 10) then + ... + else + -- timeout + end + end + end diff --git a/doc/sphinx/reference/fiber.rst b/doc/sphinx/reference/fiber.rst new file mode 100644 index 0000000000000000000000000000000000000000..1b7a105a463d60c9943a1bc7fd7903b61e36332f --- /dev/null +++ b/doc/sphinx/reference/fiber.rst @@ -0,0 +1,262 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `fiber` +------------------------------------------------------------------------------- + +The ``fiber`` package allows for creating, running and managing *fibers*. + +A fiber is a set of instructions which are executed with cooperative +multitasking. Fibers managed by the fiber package are associated with +a user-supplied function called the *fiber function*. +A fiber has three possible states: **running**, **suspended** or **dead**. +When a fiber is created with ``fiber.create()``, it is running. +When a fiber yields control with ``fiber.sleep()``, it is suspended. +When a fiber ends (because the fiber function ends), it is dead. + +All fibers are part of the fiber registry. This registry can be searched +(``fiber.find()``) - via fiber id (fid), which is numeric. + +A runaway fiber can be stopped with ``fiber_object:cancel()``. However, +``fiber_object:cancel()`` is advisory — it works only if the runaway fiber +calls ``fiber.testcancel()`` once in a while. Most box.* functions, such +as ``box.space...delete()`` or ``box.space...update()``, do call +``fiber.testcancel()`` but ``box.space...select{}`` does not. In practice, +a runaway fiber can only become unresponsive if it does many computations +and does not check whether it's been canceled. + +The other potential problem comes from fibers which never get scheduled, +because they are not subscribed to any events, or because no relevant +events occur. Such morphing fibers can be killed with ``fiber.cancel()`` +at any time, since ``fiber.cancel()`` sends an asynchronous wakeup event +to the fiber, and ``fiber.testcancel()`` is checked whenever such an event occurs. + +Like all Lua objects, dead fibers are garbage collected. The garbage collector +frees pool allocator memory owned by the fiber, resets all fiber data, and +returns the fiber (now called a fiber carcass) to the fiber pool. The carcass +can be reused when another fiber is created. + +.. module:: fiber + +.. function:: create(function [, function-arguments]) + + Create and start a fiber. The fiber is created and begins to run immediately. + + :param function: the function to be associated with the fiber + :param function-arguments: what will be passed to function + :return: created fiber object + :rtype: userdata + + .. code-block:: lua + + fiber_object = fiber.create(function_name) + +.. function:: self() + + :return: fiber object for the currently scheduled fiber. + :rtype: userdata + +.. function:: find(id) + + :param id: scalar value to find thread by. + :return: fiber object for the specified fiber. + :rtype: userdata + +.. function:: sleep(time) + + Yield control to the scheduler and sleep for the specified number + of seconds. Only the current fiber can be made to sleep. + + :param time: number of seconds to sleep. + +.. function:: yield() + + Yield control to the scheduler. Equivalent to ``fiber.sleep(0)``. + +.. function:: status() + + Return the status of the current fiber. + + :return: the status of ``fiber``. One of: + “deadâ€, “suspendedâ€, or “runningâ€. + :rtype: string + +.. function:: info() + + Return information about all fibers. + + :return: the name, id, and backtrace of all fibers. + :rtype: table + +.. function:: kill(id) + + Locate a fiber by its numeric id and cancel it. In other words, + ``fiber.kill()`` combines ``fiber.find()`` and ``fiber_object:cancel()``. + + :param id: the id of the fiber to be canceled. + :exception: the specified fiber does not exist or cancel is not permitted. + +.. function:: testcancel() + + Check if the current fiber has been canceled + and throw an exception if this is the case. + +.. class:: fiber_object + + .. method:: id() + + :param self: fiber object, for example the fiber + object returned by ``fiber.create`` + :return: id of the fiber. + :rtype: number + + .. method:: name() + + :param self: fiber object, for example the fiber + object returned by ``fiber.create`` + :return: name of the fiber. + :rtype: number + + .. method:: name(name) + + Change the fiber name. By default the Tarantool server's + interactive-mode fiber is named 'interactive' and new + fibers created due to ``fiber.create`` are named 'lua'. + Giving fibers distinct names makes it easier to + distinguish them when using ``fiber.info``. + + :param self: fiber object, for example the fiber + object returned by ``fiber.create`` + :param string name: the new name of the fiber. + :return: nil + + .. method:: status() + + Return the status of the specified fiber. + + :param self: fiber object, for example the fiber + object returned by ``fiber.create`` + :return: the status of fiber. One of: “deadâ€, + “suspendedâ€, or “runningâ€. + :rtype: string + + .. method:: cancel() + + Cancel a fiber. Running and suspended fibers can be canceled. + After a fiber has been canceled, attempts to operate on it will + cause errors, for example ``fiber_object:id()`` will cause + "error: the fiber is dead". + + :param self: fiber object, for example the fiber + object returned by ``fiber.create`` + :return: nil + + :exception: cancel is not permitted for the specified fiber object. + +.. function:: time() + + :return: current system time (in seconds since the epoch) as a Lua + number. The time is taken from the event loop clock, + which makes this call very cheap, but still useful for + constructing artificial tuple keys. + :rtype: num + + .. code-block:: lua + + tarantool> fiber = require('fiber') + --- + ... + tarantool> fiber.time(), fiber.time() + --- + - 1385758759.2591 + - 1385758759.2591 + ... + +.. function:: time64() + + :return: current system time (in microseconds since the epoch) + as a 64-bit integer. The time is taken from the event + loop clock. + :rtype: num + + .. code-block:: lua + + tarantool> fiber = require('fiber') + --- + ... + tarantool> fiber.time(), fiber.time64() + --- + - 1385758828.9825 + - 1385758828982485 + ... + +================================================= + Example +================================================= + +Make the function which will be associated with the fiber. This function +contains an infinite loop ("while 0 == 0" is always true). Each iteration +of the loop adds 1 to a global variable named gvar, then goes to sleep for +2 seconds. The sleep causes an implicit ``fiber.yield()``. + +.. code-block:: lua + + tarantool> fiber = require('fiber') + tarantool> console = require('console'); console.delimiter('!') + tarantool> function function_x() + -> gvar = 0 + -> while 0 == 0 do + -> gvar = gvar + 1 + -> fiber.sleep(2) + -> end + -> end! + --- + ... + tarantool> console.delimiter('')! + +Make a fiber, associate function_x with the fiber, and start function_x. +It will immediately "detach" so it will be running independently of the caller. + +.. code-block:: lua + + tarantool> fiber_of_x = fiber.create(function_x) + --- + ... + +Get the id of the fiber (fid), to be used in later displays. + +.. code-block:: lua + + tarantool> fid = fiber_of_x:id() + --- + ... + +Pause for a while, while the detached function runs. Then ... Display the fiber +id, the fiber status, and gvar (gvar will have gone up a bit depending how long +the pause lasted). The status is suspended because the fiber spends almost all +its time sleeping or yielding. + +.. code-block:: lua + + tarantool> print('#',fid,'. ',fiber_of_x:status(),'. gvar=',gvar) + # 102 . suspended . gvar= 399 + --- + ... + +Pause for a while, while the detached function runs. Then ... Cancel the fiber. +Then, once again ... Display the fiber id, the fiber status, and gvar (gvar +will have gone up a bit more depending how long the pause lasted). This time +the status is dead because the cancel worked. + +.. code-block:: lua + + tarantool> fiber_of_x:cancel() + ... fiber `lua' has been cancelled + ... fiber `lua': exiting + --- + ... + tarantool> print('#',fid,'. ',fiber_of_x:status(),'. gvar=',gvar) + # 102 . dead . gvar= 421 + --- + ... diff --git a/doc/sphinx/reference/fio.rst b/doc/sphinx/reference/fio.rst new file mode 100644 index 0000000000000000000000000000000000000000..79b740565e9306a395a428f4cb68e32e720d3dc0 --- /dev/null +++ b/doc/sphinx/reference/fio.rst @@ -0,0 +1,431 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `fio` +------------------------------------------------------------------------------- + +Tarantool supports file input/output with an API that is similar to POSIX +syscalls. All operations are performed asynchronously. Multiple fibers can +access the same file simultaneously. + +.. module:: fio + +================================================= + Common pathname manipulations +================================================= + +.. function:: pathjoin(partial-string [, partial-string ...]) + + Concatenate partial string, separated by '/' to form a path name. + + :param string partial-string: one or more strings to be concatenated. + :return: path name + :rtype: string + + .. code-block:: lua + + tarantool> fio.pathjoin('/etc', 'default', 'myfile') + --- + - /etc/default/myfile + ... + +.. function:: basename(path-name[, suffix]) + + Given a full path name, remove all but the final part (the file name). + Also remove the suffix, if it is passed. + + :param string path-name: path name + :param string suffix: suffix + + :return: file name + :rtype: string + + .. code-block:: lua + + tarantool> fio.basename('/path/to/my.lua', '.lua') + --- + - my + ... + +.. function:: dirname(path-name) + + Given a full path name, remove the final part (the file name). + + :param string path-name: path name + + :return: directory name, that is, path name except for file name. + :rtype: string + + .. code-block:: lua + + tarantool> fio.dirname('/path/to/my.lua') + --- + - /path/to/ + ... + +================================================= + Common file manipulations +================================================= + +.. function:: umask(mask-bits) + + Set the mask bits used when creating files or directories. For a detailed + description type "man 2 umask". + + :param number mask-bits: mask bits. + :return: previous mask bits. + :rtype: number + + .. code-block:: lua + + tarantool> fio.umask(tonumber('755', 8)) -- pass 755 octal + --- + - 493 + ... + +.. function:: lstat(path-name) + stat(path-name) + + Returns information about a file object. For details type "man 2 lstat" or + "man 2 stat". + + :param string path-name: path name of file. + :return: fields which describe the file's block size, creation time, size, + and other attributes. + :rtype: table + + .. code-block:: lua + + tarantool> fio.lstat('/etc') + --- + - inode: 1048577 + rdev: 0 + size: 12288 + atime: 1421340698 + mode: 16877 + mtime: 1424615337 + nlink: 160 + uid: 0 + blksize: 4096 + gid: 0 + ctime: 1424615337 + dev: 2049 + blocks: 24 + ... + +.. function:: mkdir(path-name) + rmdir(path-name) + + Create or delete a directory. For details type + "man 2 mkdir" or "man 2 rmdir". + + :param string path-name: path of directory. + :return: true if success, false if failure. + :rtype: boolean + + .. code-block:: lua + + tarantool> fio.mkdir('/etc') + --- + - false + ... + + +.. function:: glob(path-name) + + Return a list of files that match an input string. The list is constructed + with a single flag that controls the behavior of the function: GLOB_NOESCAPE. + For details type "man 3 glob". + + :param string path-name: path-name, which may contain wildcard characters. + :return: list of files whose names match the input string + :rtype: table + :except: nil on failure. + + .. code-block:: lua + + tarantool> fio.glob('/etc/x*') + --- + - - /etc/xdg + - /etc/xml + - /etc/xul-ext + ... + + +.. function:: tempdir() + + Return the name of a directory that can be used to store temporary files. + + .. code-block:: lua + + tarantool> fio.tempdir() + --- + - /tmp/lG31e7 + ... + +.. function:: link (src , dst) + symlink (src , dst) + readlink (src) + unlink (src) + + Functions to create and delete links. For details type "man readlink", + "man 2 link", "man 2 symlink", "man 2 unlink".. + + :param string src: existing file name. + :param string dst: linked name. + + :return: ``fio.link`` and ``fio.symlink`` and ``fio.unlink`` return true if + success, false if failure. ``fio.readlink`` returns the link value + if success, nil if failure. + + .. code-block:: lua + + tarantool> fio.link('/home/username/tmp.txt', '/home/username/tmp.txt2') + --- + - true + ... + tarantool> fio.unlink('/home/pgulutzan/tmp.txt2') + --- + - true + ... + +.. function:: rename(path-name, new-path-name) + + Rename a file or directory. For details type "man 2 rename". + + :param string path-name: original name. + :param string new-path-name: new name. + + :return: true if success, false if failure. + :rtype: boolean + + .. code-block:: lua + + tarantool> fio.rename('/home/username/tmp.txt', '/home/username/tmp.txt2') + --- + - true + ... + +.. function:: chown(path-name, owner-user, owner-group) + chmod(path-name, new-rights) + + Manage the rights to file objects, or ownership of file objects. + For details type "man 2 chown" or "man 2 chmod". + + :param string owner-user: new user uid. + :param string owner-group: new group uid. + :param number new-rights: new permissions + + .. code-block:: lua + + tarantool> fio.chmod('/home/username/tmp.txt', tonumber('0755', 8)) + --- + - true + ... + fio.chown('/home/username/tmp.txt', 'username', 'username') + --- + - true + ... + +.. function:: truncate(path-name, new-size) + + Reduce file size to a specified value. For details type "man 2 truncate". + + :param string path-name: + :param number new-size: + + :return: true if success, false if failure. + :rtype: boolean + + .. code-block:: lua + + tarantool> fio.truncate('/home/username/tmp.txt', 99999) + --- + - true + ... + +.. function:: sync() + + Ensure that changes are written to disk. For details type "man 2 sync". + + :return: true if success, false if failure. + :rtype: boolean + + .. code-block:: lua + + tarantool> fio.sync() + --- + - true + ... + +.. function:: open(path-name [, flags]) + + Open a file in preparation for reading or writing or seeking. + + :param string path-name: + :param number flags: Flags can be passed as a number or as string + constants, for example '``O_RDONLY``', + '``O_WRONLY``', '``O_RDWR``'. Flags can be + combined by enclosing them in braces. + :return: file handle (later - fh) + :rtype: userdata + :except: nil + + .. code-block:: lua + + tarantool> fh = fio.open('/home/username/tmp.txt', {'O_RDWR', 'O_APPEND'}) + --- + ... + tarantool> fh -- display file handle returned by fio.open + --- + - fh: 11 + ... + +.. class:: file-handle + + .. method:: close() + + Close a file that was opened with ``fio.open``. For details type "man 2 close". + + :param userdata fh: file-handle as returned by ``fio.open()``. + :return: true if success, false on failure. + :rtype: boolean + + .. code-block:: lua + + tarantool> fh:close() -- where fh = file-handle + --- + - true + ... + + .. method:: pread(count, offset) + pwrite(new-string, offset) + + Perform read/write random-access operation on a file, without affecting + the current seek position of the file. + For details type "man 2 pread" or "man 2 pwrite". + + :param userdata fh: file-handle as returned by ``fio.open()``. + :param number count: number of bytes to read + :param string new-string: value to write + :param number offset: offset within file where reading or writing begins + :return: ``fh:pwrite`` returns true if success, false if failure. + ``fh:pread`` returns the data that was read, or nil if failure. + + .. code-block:: lua + + tarantool> fh:pread(25, 25) + --- + - |- + elete from t8// + insert in + ... + + .. method:: read(count) + write(new-string) + + Perform non-random-access read or write on a file. For details type + "man 2 read" or "man 2 write". + + .. NOTE:: + + ``fh:read`` and ``fh:write`` affect the seek position within the + file, and this must be taken into account when working on the same + file from multiple fibers. It is possible to limit or prevent file + access from other fibers with ``fiber.ipc``. + + :param userdata fh: file-handle as returned by ``fio.open()``. + :param number count: number of bytes to read + :param string new-string: value to write + :return: ``fh:write`` returns true if success, false if failure. + ``fh:read`` returns the data that was read, or nil if failure. + + .. code-block:: lua + + tarantool> fh:write('new data') + --- + - true + ... + + .. method:: truncate(new-size) + + Change the size of an open file. Differs from ``fio.truncate``, which + changes the size of a closed file. + + :param userdata fh: file-handle as returned by ``fio.open()``. + :return: true if success, false if failure. + :rtype: boolean + + .. code-block:: lua + + tarantool> fh:truncate(0) + --- + - true + ... + + .. method:: seek(position [, offset-from]) + + Shift position in the file to the specified position. For details type + "man 2 seek". + + :param userdata fh: file-handle as returned by ``fio.open()``. + :param number position: position to seek to + :param string offset-from: '``SEEK_END``' = end of file, '``SEEK_CUR``' + = current position, '``SEEK_SET``' = start of file. + :return: the new position if success + :rtype: number + :except: nil + + .. code-block:: lua + + tarantool> fh:seek(20, 'SEEK_SET') + --- + - 20 + ... + + + .. method:: stat() + + Return statistics about an open file. This differs from ``fio.stat`` + which return statistics about a closed file. For details type "man 2 stat". + + :param userdata fh: file-handle as returned by ``fio.open()``. + :return: details about the file. + :rtype: table + + .. code-block:: lua + + tarantool> fh:stat() + --- + - inode: 729866 + rdev: 0 + size: 100 + atime: 1409429855 + mode: 33261 + mtime: 1409430660 + nlink: 1 + uid: 1000 + blksize: 4096 + gid: 1000 + ctime: 1409430660 + dev: 2049 + blocks: 8 + ... + + .. method:: fsync() + fdatasync() + + Ensure that file changes are written to disk, for an open file. + Compare ``fio.sync``, which is for all files. For details type + "man 2 fsync" or "man 2 fdatasync". + + :param userdata fh: file-handle as returned by ``fio.open()``. + :return: true if success, false if failure. + + .. code-block:: lua + + tarantool> fh:fsync() + --- + - true + ... diff --git a/doc/sphinx/reference/index.rst b/doc/sphinx/reference/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..5ef7cc4520053df59cfb5eb52e16eb2156613c6f --- /dev/null +++ b/doc/sphinx/reference/index.rst @@ -0,0 +1,30 @@ +------------------------------------------------------------------------------- + Library Reference +------------------------------------------------------------------------------- + +Lua_ is a light-weight, multi-paradigm, embeddable language. Stored procedures +in Lua can be used to implement data manipulation patterns or data structures. +It is possible to dynamically define, invoke, alter and drop Lua functions. +Lua functions can run in the background and perform administrative tasks. + +.. _Lua: http://www.lua.org + +.. toctree:: + :maxdepth: 1 + + digest + uuid + json + yaml + msgpack + fiber + fiber-ipc + box_session + socket + fio + console + log + tap + pickle + other + expirationd diff --git a/doc/sphinx/reference/json.rst b/doc/sphinx/reference/json.rst new file mode 100644 index 0000000000000000000000000000000000000000..075909e90ba06d9f6616d44c4b56bb2b6b2c4ece --- /dev/null +++ b/doc/sphinx/reference/json.rst @@ -0,0 +1,101 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `json` +------------------------------------------------------------------------------- + +The json package provides JSON manipulation routines. It is based on the +`Lua-CJSON package by Mark Pulford`_. For a complete manual on Lua-CJSON please read +`the official documentation`_. + +.. module:: json + +.. function:: encode(lua-value) + + Convert a Lua object to a JSON string. + + :param lua_value: either a scalar value or a Lua table value. + :return: the original value reformatted as a JSON string. + :rtype: string + + .. code-block:: lua + + tarantool> json=require('json') + --- + ... + tarantool> json.encode(123) + --- + - '123' + ... + tarantool> json.encode({123}) + --- + - '[123]' + ... + tarantool> json.encode({123, 234, 345}) + --- + - '[123,234,345]' + ... + tarantool> json.encode({abc = 234, cde = 345}) + --- + - '{"cde":345,"abc":234}' + ... + tarantool> json.encode({hello = {'world'}}) + --- + - '{"hello":["world"]}' + ... + +.. function:: decode(string) + + Convert a JSON string to a Lua object. + + :param string string: a string formatted as JSON. + :return: the original contents formatted as a Lua table. + :rtype: table + + .. code-block:: lua + + tarantool> json=require('json') + --- + ... + tarantool> json.decode('123') + --- + - 123 + ... + tarantool> json.decode('[123, "hello"]')[2] + --- + - hello + ... + tarantool> json.decode('{"hello": "world"}').hello + --- + - world + ... + + +.. data:: NULL + + A value comparable to Lua "nil" which may be useful as a placeholder in a tuple. + + .. code-block:: lua + + tarantool> -- When nil is assigned to a Lua-table field, the field is null + tarantool> {nil, 'a', 'b'} + - - null + - a + - b + ... + tarantool> -- When json.NULL is assigned to a Lua-table field, the field is json.NULL + tarantool> {json.NULL, 'a', 'b'} + --- + - - null + - a + - b + ... + tarantool> -- When json.NULL is assigned to a JSON field, the field is null + tarantool> json.encode({field2 = json.NULL, field1 = 'a', field3 = 'c'}) + --- + - '{"field2":null,"field1":"a","field3":"c"}' + ... + +.. _Lua-CJSON package by Mark Pulford: http://www.kyne.com.au/~mark/software/lua-cjson.php +.. _the official documentation: http://www.kyne.com.au/~mark/software/lua-cjson-manual.html diff --git a/doc/sphinx/reference/log.rst b/doc/sphinx/reference/log.rst new file mode 100644 index 0000000000000000000000000000000000000000..e8a10e3339f3d12f1f9925f053e94b3a04ff177e --- /dev/null +++ b/doc/sphinx/reference/log.rst @@ -0,0 +1,65 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `log` +------------------------------------------------------------------------------- + +.. module:: log + +The Tarantool server puts all diagnostic messages in a log file specified by +the `logger`_ configuration parameter. Diagnostic messages may be either +system-generated by the server's internal code, or user-generated with the +``log.log_level_function_name`` function. + +.. function:: error(message) + warn(message) + info(message) + debug(message) + + Output a user-generated message to the `log file`_, given + log_level_function_name = ``error`` or ``warn`` or ``info`` or ``debug``. + + :param string message: The actual output will be a line containing the + current timestamp, a module name, 'E' or 'W' or + 'I' or 'D' or 'R' depending on + ``log_level_function_name``, and ``message``. + Output will not occur if ``log_level_function_name`` + is for a type greater than `log_level`_. + :return: nil + +.. function:: logger_pid() + +.. function:: rotate() + +================================================= + Example +================================================= + +.. code-block:: lua + + #From the shell: + #Start the server, do some requests, exit, and display the log, thus: + $ ~/tarantool/src/tarantool + tarantool> box.cfg{log_level=3, logger='tarantool.txt'} + tarantool> log = require('log') + tarantool> log.error('Error') + tarantool> log.info('Info') + tarantool> os.exit() + $ less tarantool.txt + +The output from the less command will look approximately like this: + +.. code-block:: lua + + 2...0 [5257] main/101/interactive C> version 1.6.3-355-ga4f762d + 2...1 [5257] main/101/interactive C> log level 3 + 2...1 [5261] main/101/spawner C> initialized + 2...0 [5257] main/101/interactive [C]:-1 E> Error + +The 'Error' line is visible in tarantool.txt preceded by the letter E. +The 'Info' line is not present because the log_level is 3. + +.. _logger: http://tarantool.org/doc/user_guide.html#logger +.. _log file: http://tarantool.org/doc/user_guide.html#logger +.. _log_level: http://tarantool.org/doc/user_guide.html#logger diff --git a/doc/sphinx/reference/msgpack.rst b/doc/sphinx/reference/msgpack.rst new file mode 100644 index 0000000000000000000000000000000000000000..73d0bc5577ecab37fb3876754fa4ddbe23dfc0ba --- /dev/null +++ b/doc/sphinx/reference/msgpack.rst @@ -0,0 +1,60 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `msgpack` +------------------------------------------------------------------------------- + +The ``msgpack`` package takes strings in MsgPack_ format and decodes them, or takes a +series of non-MsgPack values and encodes them. + +.. module:: msgpack + +.. function:: encode(lua_value) + + Convert a Lua object to a MsgPack string. + + :param lua_value: either a scalar value or a Lua table value. + :return: the original value reformatted as a MsgPack string. + :rtype: string + +.. function:: decode(string) + + Convert a MsgPack string to a Lua object. + + :param string: a string formatted as YAML. + :return: the original contents formatted as a Lua table. + :rtype: table + +.. data:: NULL + + A value comparable to Lua "nil" which may be useful as a placeholder in a tuple. + +================================================= + Example +================================================= + +.. code-block:: lua + + tarantool> msgpack = require('msgpack') + --- + ... + tarantool> y = msgpack.encode({'a',1,'b',2}) + --- + ... + tarantool> z = msgpack.decode(y) + --- + ... + tarantool> z[1],z[2],z[3],z[4] + --- + - a + - 1 + - b + - 2 + ... + tarantool> box.space.tester:insert{20,msgpack.NULL,20} + --- + - [20, null, 20] + ... + +.. _MsgPack: http://msgpack.org/ diff --git a/doc/sphinx/reference/other.rst b/doc/sphinx/reference/other.rst new file mode 100644 index 0000000000000000000000000000000000000000..297d672cd0008fb70a0fa5667a51b576d218e458 --- /dev/null +++ b/doc/sphinx/reference/other.rst @@ -0,0 +1,78 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Miscellaneous +------------------------------------------------------------------------------- + +.. function:: tonumber64(value) + + Convert a string or a Lua number to a 64-bit integer. The result can be + used in arithmetic, and the arithmetic will be 64-bit integer arithmetic + rather than floating-point arithmetic. (Operations on an unconverted Lua + number use floating-point arithmetic.) The ``tonumber64()`` function is + added by Tarantool; the name is global. + + .. code-block:: lua + + tarantool> type(123456789012345), type(tonumber64(123456789012345)) + --- + - number + - number + ... + tarantool> i = tonumber64('1000000000') + --- + ... + tarantool> type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2 + --- + - number + - 500000000 + - 999999998 + - 2000000000 + - 1000000002 + - 0 + - 1000000000000000000 + ... + +.. function:: dostring(lua-chunk-string [, lua-chunk-string-argument ...]) + + Parse and execute an arbitrary chunk of Lua code. This function is mainly + useful to define and run Lua code without having to introduce changes to + the global Lua environment. + + :param string lua-chunk-string: Lua code + :param lua-value lua-chunk-string-argument: zero or more scalar values + which will be appended to, or substitute for, + items in the Lua chunk. + :return: whatever is returned by the Lua code chunk. + :except: If there is a compilation error, it is raised as a Lua error. + + .. code-block:: lua + + tarantool> dostring('abc') + --- + error: '[string "abc"]:1: ''='' expected near ''<eof>''' + ... + tarantool> dostring('return 1') + --- + - 1 + ... + tarantool> dostring('return ...', 'hello', 'world') + --- + - hello + - world + ... + tarantool> console = require('console'); console.delimiter('!') + tarantool> -- This means ignore line feeds until next '!' + tarantool> -- Use `double square brackets`_ to enclose multi-line literal here! + tarantool> dostring([[local f = function(key) + -> t = box.space.tester:select{key}; + -> if t ~= nil then return t[1] else return nil end + -> end + -> return f(...)]], 1)! + --- + - null + ... + tarantool> console.delimiter('')! + +.. _double square brackets: http://www.lua.org/pil/2.4.html diff --git a/doc/sphinx/reference/pickle.rst b/doc/sphinx/reference/pickle.rst new file mode 100644 index 0000000000000000000000000000000000000000..a74f83ca0aa3d68b412a9ba996bfda1481e8095e --- /dev/null +++ b/doc/sphinx/reference/pickle.rst @@ -0,0 +1,142 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `pickle` +------------------------------------------------------------------------------- + +.. module:: pickle + +.. function:: pack(format, argument [, argument ...]) + + To use Tarantool binary protocol primitives from Lua, it's necessary to + convert Lua variables to binary format. The ``pickle.pack()`` helper + function is prototyped after Perl 'pack_'. + + + .. container:: table + + **Format specifiers** + + +------+-------------------------------------------------+ + | b, B | converts Lua variable to a 1-byte integer, | + | | and stores the integer in the resulting string | + +------+-------------------------------------------------+ + | s, S | converts Lua variable to a 2-byte integer, and | + | | stores the integer in the resulting string, | + | | low byte first | + +------+-------------------------------------------------+ + | i, I | converts Lua variable to a 4-byte integer, and | + | | stores the integer in the resulting string, low | + | | byte first | + +------+-------------------------------------------------+ + | l, L | converts Lua variable to an 8-byte integer, and | + | | stores the integer in the resulting string, low | + | | byte first | + +------+-------------------------------------------------+ + | n | converts Lua variable to a 2-byte integer, and | + | | stores the integer in the resulting string, big | + | | endian, | + +------+-------------------------------------------------+ + | N | converts Lua variable to a 4-byte integer, and | + | | stores the integer in the resulting string, big | + +------+-------------------------------------------------+ + | q, Q | converts Lua variable to an 8-byte integer, and | + | | stores the integer in the resulting string, big | + | | endian, | + +------+-------------------------------------------------+ + | f | converts Lua variable to a 4-byte float, and | + | | stores the float in the resulting string | + +------+-------------------------------------------------+ + | d | converts Lua variable to a 8-byte double, and | + | | stores the double in the resulting string | + +------+-------------------------------------------------+ + | a, A | converts Lua variable to a sequence of bytes, | + | | and stores the sequence in the resulting string | + +------+-------------------------------------------------+ + + :param string format: string containing format specifiers + :param scalar-value argument(s): scalar values to be formatted + :return: a binary string containing all arguments, + packed according to the format specifiers. + :rtype: string + + :except: unknown format specifier. + + .. code-block:: lua + + tarantool> pickle = require('pickle') + --- + ... + tarantool> box.space.tester:insert{0, 'hello world'} + --- + - [0, 'hello world'] + ... + tarantool> box.space.tester:update({0}, {{'=', 2, 'bye world'}}) + --- + - [0, 'bye world'] + ... + tarantool> box.space.tester:update({0}, {{'=', 2, pickle.pack('iiA', 0, 3, 'hello')}}) + --- + - [0, "\0\0\0\0\x03\0\0\0hello"] + ... + tarantool> box.space.tester:update({0}, {{'=', 2, 4}}) + --- + - [0, 4] + ... + tarantool> box.space.tester:update({0}, {{'+', 2, 4}}) + --- + - [0, 8] + ... + tarantool> box.space.tester:update({0}, {{'^', 2, 4}}) + --- + - [0, 12] + ... + +.. function:: unpack(format, binary-string) + + Counterpart to ``pickle.pack()``. + + :param string format: + :param string binary-string: + + :return: A list of strings or numbers. + :rtype: table + + .. code-block:: lua + + tarantool> pickle = require('pickle') + --- + ... + tarantool> -- this means following commands must end with '!' + tarantool> console = require('console'); console.delimiter('!') + tarantool> tuple = box.space.tester:replace{0}! + --- + ... + tarantool> string.len(tuple[1])! + --- + - 1 + ... + tarantool> pickle.unpack('b', tuple[1])! + --- + - 48 + ... + tarantool> pickle.unpack('bsi', pickle.pack('bsi', 255, 65535, 4294967295))! + --- + - 255 + - 65535 + - 4294967295 + ... + tarantool> pickle.unpack('ls', pickle.pack('ls', tonumber64('18446744073709551615'), 65535))! + --- + - 18446744073709551615 + - 65535 + ... + tarantool> num, str, num64 = pickle.unpack('sAl', pickle.pack('sAl', 666, 'string', + -> tonumber64('666666666666666')))! + --- + ... + tarantool> console.delimiter('') -- back to normal: commands end with line feed! + + +.. _pack: http://perldoc.perl.org/functions/pack.html diff --git a/doc/sphinx/reference/socket.rst b/doc/sphinx/reference/socket.rst new file mode 100644 index 0000000000000000000000000000000000000000..67f3c076dc6b126cec95ca0989d3ba4ef9b79e67 --- /dev/null +++ b/doc/sphinx/reference/socket.rst @@ -0,0 +1,516 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `socket` +------------------------------------------------------------------------------- + +The ``socket`` package allows exchanging data via BSD sockets with a local or +remote host in connection-oriented (TCP) or datagram-oriented (UDP) mode. +Semantics of the calls in the ``socket`` API closely follow semantics of the +corresponding POSIX calls. Function names and signatures are mostly compatible +with `luasocket`_. + +The functions for setting up and connecting are ``socket``, ``sysconnect``, +``tcp_connect``. The functions for sending data are ``send``, ``sendto``, +``write``, ``syswrite``. The functions for receiving data are ``recv``, +``recvfrom``, ``read``. The functions for waiting before sending/receiving +data are ``wait``, ``readable``, ``writable``. The functions for setting +flags are ``nonblock``, ``setsockopt``. The functions for stopping and +disconnecting are ``shutdown``, ``close``. The functions for error checking +are ``errno``, ``error``. + +.. container:: table + + **Socket functions** + + +----------------+-------------+ + | Purposes | Names | + +================+=============+ + | | socket | + | +-------------+ + | setup | sysconnect | + | +-------------+ + | | tcp_connect | + +----------------+-------------+ + | | send | + | +-------------+ + | | sendto | + | sending +-------------+ + | | write | + | +-------------+ + | | syswrite | + +----------------+-------------+ + | | recv | + | +-------------+ + | receiving | recvfrom | + | +-------------+ + | | read | + +----------------+-------------+ + | | nonblock | + | +-------------+ + | flag setting | setsockopt | + | +-------------+ + | | linger | + +----------------+-------------+ + | | listen | + | client/server +-------------+ + | | accept | + +----------------+-------------+ + | | shutdown | + | teardown +-------------+ + | | close | + +----------------+-------------+ + | | errno | + | error checking +-------------+ + | | errno | + +----------------+-------------+ + | | getaddrinfo | + | +-------------+ + | | getsockopt | + | information +-------------+ + | | peer | + | +-------------+ + | | name | + +----------------+-------------+ + + +Typically a socket session will begin with the setup functions, will set one +or more flags, will have a loop with sending and receiving functions, will +end with the teardown functions -- as an example at the end of this section +will show. Throughout, there may be error-checking and waiting functions for +synchronization. Some functions may "block" if a non-default option flag is +set, therefore the fiber that they are in will yield so that other processes +may take over, as is the norm for cooperative multitasking. + +For all examples in this section the socket name will be sock and +the function invocations will look like ``sock:function_name(...)``. + +.. module:: socket + +.. function:: __call(domain, type, protocol) + + Create a new TCP or UDP socket. The argument values + are the same as in the `Linux man page <http://man7.org/linux/man-pages/man2/socket.2.html>`_. + + :param domain: + :param type: + :param protocol: + :return: a new socket, or nil. + :rtype: userdata + +.. function:: tcp_connect(host, port) + tcp_connect(host) + + Connect a socket to a remote host. + + :param string host: URL or IP address + :param number port: port number + :return: a connected socket, if no error. + :rtype: userdata + +.. function:: getaddrinfo(host, type, [, {option-list}]) + + The ``socket.getaddrinfo()`` function is useful for finding information + about a remote site so that the correct arguments for + ``sock:sysconnect()`` can be passed. + + :return: A table containing these fields: "host", "family", "type", "protocol", "port". + :rtype: table + + .. code-block:: lua + + tarantool> socket.getaddrinfo('tarantool.org', 'http') + + will return variable information such as + + .. code-block:: yaml + + --- + - - host: 188.93.56.70 + family: AF_INET + type: SOCK_STREAM + protocol: tcp + port: 80 + - host: 188.93.56.70 + family: AF_INET + type: SOCK_DGRAM + protocol: udp + port: 80 + ... + +.. function:: tcp_server(host, port, handler-function) + + The ``socket.tcp_server()`` function makes Tarantool act as a server that + can accept connections. Usually the same objective + is accomplished with ``box.cfg{listen=...)``. + + .. code-block:: lua + + socket.tcp_server('localhost', 3302, function () end). + + +.. class:: socket_object + + .. method:: sysconnect(host, port) + + Connect a socket to a remote host. The argument values are the same as + in the `Linux man page <http://man7.org/linux/man-pages/man2/connect.2.html>`_. + The host must be an IP address. + + Parameters: + * Either: + * host - a string representation of an IPv4 address + or an IPv6 address; + * port - a number. + * Or: + * host - a string containing "unix/"; + * port - a string containing a path to a unix socket. + * Or: + * host - a number, 0 (zero), meaning "all local + interfaces"; + * port - a number. If a port number is 0 (zero), + the socket will be bound to a random local port. + + + :return: a connected socket, if no error. + :rtype: userdata + + .. code-block:: lua + + sock:sysconnect('127.0.0.1', 80) + + .. method:: send(data) + + Send data over a connected socket. + + :param string data: + :return: true if success, false if error. + :rtype: boolean + + .. NOTE:: + + The function ``sock:write(...)`` has + the same parameters and same effect. + + .. method:: syswrite(size) + + Write as much as possible data to the socket buffer if non-blocking. + Rarely used. For details see `this description`_. + + .. method:: recv(size) + + Read ``size`` bytes from a connected socket. An internal read-ahead + buffer is used to reduce the cost of this call. + + :param integer size: + :return: a string of the requested length on success. + :rtype: string + :exception: On error, returns an empty string, followed by status, + errno, errstr. In case the writing side has closed its + end, returns the remainder read from the socket (possibly + an empty string), followed by "eof" status. + + .. method:: read(limit [, timeout]) + read(delimiter [, timeout]) + read({limit=limit} [, timeout]) + read({delimiter=delimiter} [,timeout]) + read({limit=limit, delimiter=delimiter} [, timeout]) + + Read from a connected socket until some condition is true, and return + the bytes that were read. + Reading goes on until ``limit`` bytes have been read, or a delimiter + has been read, or a timeout has expired. + + :param integer limit: maximum number of bytes to read for + example 50 means "stop after 50 bytes" + :param string delimiter: separator or `Lua pattern`_ for example + '[0-9]' means "stop after a digit" + :param number timeout: maximum number of seconds to wait for + example 50 means "stop after 50 seconds". + + :return: an empty string if there is nothing more to read, or a nil + value if error, or a string up to ``limit`` bytes long, + which may include the bytes that matched the ``delimiter`` + expression. + :rtype: string + + .. method:: sysread(size) + + Return all available data from the socket buffer if non-blocking. + Rarely used. For details see `this description`_. + + .. method:: bind(host [, port]) + + Bind a socket to the given host/port. A UDP socket after binding + can be used to receive data (see :meth:`socket_object.recvfrom()`). + A TCP socket can be used to accept new connections, after it has + been put in listen mode. + + :param host: + :param port: + + :return: a socket object on success + :rtype: userdata + :exception: nil, status, errno, errstr on error. + + + .. method:: listen(backlog) + + Start listening for incoming connections. + + :param backlog: On Linux the listen ``backlog`` backlog may be from + /proc/sys/net/core/somaxconn, on BSD the backlog + may be ``SOMAXCONN``. + + :return: true for success, false for error. + :rtype: boolean + + .. method:: accept() + + Accept a new client connection and create a new connected socket. + It is good practice to set the socket's blocking mode explicitly + fter accepting. + + :return: new socket if success. + :rtype: userdata + :exception: nil + + .. method:: sendto(host, port, data) + + Send a message on a UDP socket to a specified host. + + :param string host: + :param number port: + :param string data: + + :return: the number of bytes sent. + :rtype: number + :exception: status, errno, errstr. + + .. method:: recvfrom(limit) + + Receive a message on a UDP socket. + + :param integer limit: + :return: message, a table containing "host", "family" and "port" fields. + :rtype: string, table + :exception: status, errno, errstr. + + After + + .. code-block:: lua + + message_content, message_sender = recvfrom(1) + + the value of ``message_content`` might be a string containing 'X' and + the value of ``message_sender`` might be a table containing + ``message_sender.host = '18.44.0.1'``, + ``message_sender.family = 'AF_INET'``, + ``message_sender.port = 43065``. + + .. method:: shutdown(how) + + Shutdown a reading end, a writing end, or both ends of a socket. + + :param how: socket.SHUT_RD, socket.SHUT_WR, or socket.SHUT_RDWR. + + :return: true or false. + :rtype: boolean + + .. method:: close() + + Close (destroy) a socket. A closed socket should not be used any more. + A socket is closed automatically when its userdata is garbage collected by Lua. + + :return: true on success, false on error. For example, if + sock is already closed, sock:close() returns false. + :rtype: boolean + + .. method:: error() + errno() + + Retrieve information about the last error that occurred on a socket, if any. + Errors do not cause throwing of exceptions so these functions are usually necessary. + + :return: result for ``sock:errno()``, result for ``sock:error()``. + If there is no error, then ``sock:errno()`` will return 0 and ``sock:error()``. + :rtype: number, string + + .. method:: setsockopt(level, name, value) + + Set socket flags. The argument values are the same as in the + `Linux man page <http://man7.org/linux/man-pages/man2/setsockopt.2.html>`_. + The ones that Tarantool accepts are: + + * SO_ACCEPTCONN + * SO_BINDTODEVICE + * SO_BROADCAST + * SO_BSDCOMPAT + * SO_DEBUG + * SO_DOMAIN + * SO_ERROR + * SO_DONTROUTE + * SO_KEEPALIVE + * SO_MARK + * SO_OOBINLINE + * SO_PASSCRED + * SO_PEERCRED + * SO_PRIORITY + * SO_PROTOCOL + * SO_RCVBUF + * SO_RCVBUFFORCE + * SO_RCVLOWAT + * SO_SNDLOWAT + * SO_RCVTIMEO + * SO_SNDTIMEO + * SO_REUSEADDR + * SO_SNDBUF + * SO_SNDBUFFORCE + * SO_TIMESTAMP + * SO_TYPE + + Setting SO_LINGER is done with ``sock:linger(active)``. + + .. method:: getsockopt(level, name) + + Get socket flags. For a list of possible flags see ``sock:setsockopt()``. + + .. method:: linger([active]) + + Set or clear the SO_LINGER flag. For a description of the flag, see + `Linux man page <http://man7.org/linux/man-pages/man1/loginctl.1.html>`_. + + :param boolean active: + + :return: new active and timeout values. + + .. method:: nonblock([flag]) + + ``sock:nonblock()`` returns the current flag value. |br| + ``sock:nonblock(false)`` sets the flag to false and returns false. |br| + ``sock:nonblock(true)`` sets the flag to true and returns true. + This function may be useful before invoking a function which might + otherwise block indefinitely. + + .. method:: readable([timeout]) + writeable([timeout]) + wait([timout]) + + ``sock:readable()`` waits until something is readable, or until a timeout value expires. |br| + ``sock:writable()`` waits until something is writable, or until a timeout value expires. |br| + ``sock:wait()`` waits until something is either readable or writable, or until a timeout value expires. + + .. method:: name() + + The ``The sock:name()`` function is used to get information about the + near side of the connection. If a socket was bound to ``xyz.com:45``, + then ``sock:name`` will return information about ``[host:xyz.com, port:45]``. + The equivalent POSIX function is ``getsockname()``. + + :return: A table containing these fields: "host", "family", "type", "protocol", "port". + :rtype: table + + .. method:: peer() + + The ``sock:peer()`` function is used to get information about the far side of a connection. + If a TCP connection has been made to a distant host ``tarantool.org:80``, ``sock:peer()`` + will return information about ``[host:tarantool.org, port:80]``. + The equivalent POSIX function is ``getpeername()``. + + :return: A table containing these fields: "host", "family", "type", "protocol", "port". + :rtype: table + +.. _Lua pattern: http://www.lua.org/pil/20.2.html +.. _this description: https://github.com/tarantool/tarantool/wiki/sockets%201.6 + +================================================= + Example +================================================= + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Use of a TCP socket over the Internet +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this example a connection is made over the internet between the Tarantool +server and tarantool.org, then an HTTP "head" message is sent, and a response +is received: "``HTTP/1.1 200 OK``". This is not a useful way to communicate +with this particular site, but shows that the system works. + + +.. code-block:: lua + + tarantool> socket = require('socket') + --- + ... + tarantool> sock = socket.tcp_connect('tarantool.org', 80) + --- + ... + tarantool> type(sock) + --- + - table + ... + tarantool> sock:error() + --- + - null + ... + tarantool> sock:send("HEAD / HTTP/1.0\r\nHost: tarantool.org\r\n\r\n") + --- + - true + ... + tarantool> sock:read(17) + --- + - "HTTP/1.1 200 OK\r\n" + ... + tarantool> sock:close() + --- + - true + ... + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Use of a UDP socket on localhost +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here is an example with datagrams. Set up two connections on 127.0.0.1 +(localhost): ``sock_1`` and ``sock_2``. Using ``sock_2``, send a message +to ``sock_1``. Using ``sock_1``, receive a message. Display the received +message. Close both connections. |br| This is not a useful way for a +computer to communicate with itself, but shows that the system works. + +.. code-block:: lua + + tarantool> socket = require('socket') + --- + ... + tarantool> sock_1 = socket('AF_INET', 'SOCK_DGRAM', 'udp') + --- + ... + tarantool> sock_1:bind('127.0.0.1') + --- + - true + ... + tarantool> sock_2 = socket('AF_INET', 'SOCK_DGRAM', 'udp') + --- + ... + tarantool> sock_2:sendto('127.0.0.1', sock_1:name().port,'X') + --- + - true + ... + tarantool> message = sock_1:recvfrom() + --- + ... + tarantool> message + --- + - X + ... + tarantool> sock_1:close() + --- + - true + ... + tarantool> sock_2:close() + --- + - true + ... + + +.. _luasocket: https://github.com/diegonehab/luasocket diff --git a/doc/sphinx/reference/tap.rst b/doc/sphinx/reference/tap.rst new file mode 100644 index 0000000000000000000000000000000000000000..04ff65c71a61495c9f98a50a4a962b7a20bff0b3 --- /dev/null +++ b/doc/sphinx/reference/tap.rst @@ -0,0 +1,207 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `tap` +------------------------------------------------------------------------------- + +The tap package streamlines the testing of other packages. It allows writing of +tests in the `TAP protocol`_. The results from the tests can be parsed by +standard TAP-analyzers so they can be passed to utilities such as `prove`_. Thus +one can run tests and then use the results for statistics, decision-making, and so on. + +.. module:: tap + +.. function:: test(test-name) + + Initialize. |br| + The result of ``tap.test`` is an object, which will be called taptest + in the rest of this discussion, which is necessary for + ``taptest:plan()`` and all the other methods. + + :param string test-name: an arbitrary name to give for the test outputs. + :return: taptest + :rtype: userdata + + .. code-block:: lua + + tap = require('tap') + taptest = tap.test('test-name') + +.. class:: taptest + + .. method:: plan(count) + + Indicate how many tests will be performed. + + :param number count: + :return: nil + + .. method:: check() + + Checks the number of tests performed. This check should only be done + after all planned tests are complete, so ordinarily ``taptest:check()`` + will only appear at the end of a script. + + Will display ``# bad plan: ...`` if the number of completed tests is not + equal to the number of tests specified by ``taptest:plan(...)``. + + :return: nil + + .. method:: diag(message) + + Display a diagnostic message. + + :param string message: the message to be displayed. + :return: nil + + .. method:: ok(condition, test-name) + + This is a basic function which is used by other functions. Depending + on the value of ``condition``, print 'ok' or 'not ok' along with + debugging information. Displays the message. + + :param boolean condition: an expression which is true or false + :param string test-name: name of test + + :return: true or false. + :rtype: boolean + + .. code-block:: lua + + tarantool> taptest:ok(true,'x') + ok - x + --- + - true + ... + tarantool> tap = require('tap') + --- + ... + tarantool> taptest = tap.test('test-name') + TAP version 13 + --- + ... + tarantool> taptest:ok(1 + 1 == 2, 'X') + ok - X + --- + - true + ... + + .. method:: fail(test-name) + + ``taptest:fail('x')`` is equivalent to ``taptest:ok(false, 'x')``. + Displays the message. + + :param string test-name: name of test + + :return: true or false. + :rtype: boolean + + .. method:: skip(message) + + ``taptest:skip('x')`` is equivalent to + ``taptest:ok(true, 'x' .. '# skip')``. + Displays the message. + + :param string test-name: name of test + + :return: nil + + .. code-block:: lua + + tarantool> taptest:skip('message') + ok - message # skip + --- + - true + ... + + .. method:: is(got, expected, test-name) + + Check whether the first argument equals the second argument. + Displays extensive message if the result is false. + + :param number got: actual result + :param number expected: expected result + :param string test-name: name of test + :return: true or false. + :rtype: boolean + + .. method:: isnt(got, expected, test-name) + + This is the negation of ``taptest:is(...)``. + + :param number got: actual result + :param number expected: expected result + :param string test-name: name of test + + :return: true of false. + :rtype: boolean + + .. method:: isnil(value, test-name) + isstring(value, test-name) + isnumber(value, test-name) + istable(value, test-name) + isboolean(value, test-name) + isudata(value, test-name) + iscdata(value, test-name) + + Test whether a value has a particular type. Displays a long message if + the value is not of the specified type. + + :param lua-value value: + :param string test-name: name of test + + :return: true of false. + :rtype: boolean + + .. method:: is_deeply(got, expected, test-name) + + Recursive version of ``tap-test:is(...)``, which can be be used to + compare tables as well as scalar values. + + :return: true of false. + :rtype: boolean + + :param lua-value got: actual result + :param lua-value expected: expected result + :param string test-name: name of test + + +.. _prove: https://metacpan.org/pod/distribution/Test-Harness/bin/prove +.. _TAP protocol: https://en.wikipedia.org/wiki/Test_Anything_Protocol + +================================================= + Example +================================================= + +To run this example: put the script in a file named ./tap.lua, then make +tap.lua executable by saying ``chmod a+x ./tap.lua``, then execute using +Tarantool as a script processor by saying ./tap.lua. + +.. code-block:: lua + + #!/usr/bin/tarantool + local tap = require('tap') + test = tap.test("my test name") + test:plan(2) + test:ok(2 * 2 == 4, "2 * 2 is 4") + test:test("some subtests for test2", function(test) + test:plan(2) + test:is(2 + 2, 4, "2 + 2 is 4") + test:isnt(2 + 3, 4, "2 + 3 is not 4") + end) + test:check() + +The output from the above script will look approximately like this: + +.. code-block:: tap + + TAP version 13 + 1..2 + ok - 2 * 2 is 4 + # Some subtests for test2 + 1..2 + ok - 2 + 2 is 4, + ok - 2 + 3 is not 4 + # Some subtests for test2: end + ok - some subtests for test2 diff --git a/doc/sphinx/reference/uuid.rst b/doc/sphinx/reference/uuid.rst new file mode 100644 index 0000000000000000000000000000000000000000..c40bb52d9e1a89d8e64ba2265595f48ad3b1e1d0 --- /dev/null +++ b/doc/sphinx/reference/uuid.rst @@ -0,0 +1,105 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `uuid` +------------------------------------------------------------------------------- + +A "UUID" is a `Universally unique identifier`_. If an application requires that +a value be unique only within a single computer or on a single database, then a +simple counter is better than a UUID, because getting a UUID is time-consuming +(it requires a syscall_). For clusters of computers, or widely distributed +applications, UUIDs are better. + +The functions that can return a UUID are: ``uuid()``, ``uuid.bin()``, ``uuid.str()``. |br| +The functions that can convert between different types of UUID are: ``:bin()``, ``:str()``, ``uuid.fromstr()``, ``uuid.frombin()``. |br| +The function that can determine whether a UUID is an all-zero value is: ``:isnil()``. + +.. module:: uuid + +.. data:: nil + + A nil object + +.. function:: __call() + + :return: a UUID + :rtype: cdata + +.. function:: bin() + + :return: a UUID + :rtype: 16-byte string + +.. function:: str() + + :return: a UUID + :rtype: 36-byte binary string + +.. function:: fromstr(uuid_str) + + :param uuid_str: UUID in 36-byte hexademical string + :return: converted UUID + :rtype: cdata + +.. function:: frombin(uuid_bin) + + :param uuid_str: UUID in 16-byte binary string + :return: converted UUID + :rtype: cdata + +.. class:: uuid_cdata + + .. method:: bin([byte-order]) + + :param byte-order: |br| 'l' - little-endian, + |br| 'b' - big-endian, + |br| 'h' - endianness depends on host (default), + |br| 'n' - endianness depends on network + + :return: UUID converted from cdata input value. + :rtype: 16-byte binary string + + .. method:: str() + + :return: UUID converted from cdata input value. + :rtype: 36-byte hexadecimal string + + .. method:: isnil() + + The all-zero UUID value can be expressed as uuid.NULL, or as + ``uuid.fromstr('00000000-0000-0000-0000-000000000000')``. + The comparison with an all-zero value can also be expressed as + ``uuid_with_type_cdata == uuid.NULL``. + + :return: true if the value is all zero, otherwise false. + :rtype: bool + +================================================= + Example +================================================= + +.. code-block:: lua + + tarantool> uuid = require('uuid') + --- + ... + tarantool> uuid(), uuid.bin(), uuid.str() + --- + - 16ffedc8-cbae-4f93-a05e-349f3ab70baa + - !!binary FvG+Vy1MfUC6kIyeM81DYw== + - 67c999d2-5dce-4e58-be16-ac1bcb93160f + ... + tarantool> uu = uuid() + --- + ... + tarantool> #uu:bin(), #uu:str(), type(uu), uu:isnil() + --- + - 16 + - 36 + - cdata + - false + ... + +.. _Universally unique identifier: https://en.wikipedia.org/wiki/Universally_unique_identifier +.. _syscall: https://en.wikipedia.org/wiki/Syscall diff --git a/doc/sphinx/reference/yaml.rst b/doc/sphinx/reference/yaml.rst new file mode 100644 index 0000000000000000000000000000000000000000..a4e2d269ed27709d4c14c0e8767b561ccc0e883b --- /dev/null +++ b/doc/sphinx/reference/yaml.rst @@ -0,0 +1,60 @@ +.. include:: ../directives.rst +.. highlight:: lua + +------------------------------------------------------------------------------- + Package `yaml` +------------------------------------------------------------------------------- + +The ``yaml`` package takes strings in YAML_ format and decodes them, or takes a +series of non-YAML values and encodes them. + +.. module:: yaml + +.. function:: encode(lua_value) + + Convert a Lua object to a YAML string. + + :param lua_value: either a scalar value or a Lua table value. + :return: the original value reformatted as a YAML string. + :rtype: string + +.. function:: decode(string) + + Convert a YAML string to a Lua object. + + :param string: a string formatted as YAML. + :return: the original contents formatted as a Lua table. + :rtype: table + +.. data:: NULL + + A value comparable to Lua "nil" which may be useful as a placeholder in a tuple. + +================================================= + Example +================================================= + +.. code-block:: lua + + tarantool> yaml = require('yaml') + --- + ... + tarantool> y = yaml.encode({'a',1,'b',2}) + --- + ... + tarantool> z = yaml.decode(y) + --- + ... + tarantool> z[1],z[2],z[3],z[4] + --- + - a + - 1 + - b + - 2 + ... + tarantool> if yaml.NULL == nil then print('hi') end + hi + --- + ... + +.. _YAML: http://yaml.org/ diff --git a/doc/user/data-model.xml b/doc/user/data-model.xml index 1688352de019fcf63a121f329adf0a6e181b9cd5..be1f1fc43a31a3d1925a0f6c6bb5e245c7efb341 100644 --- a/doc/user/data-model.xml +++ b/doc/user/data-model.xml @@ -158,7 +158,7 @@ The syntax details for defining spaces and indexes are in section 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 <link linkend="tonumber64">tonumber64</link> function. + 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> @@ -173,9 +173,9 @@ The syntax details for defining spaces and indexes are in section 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 - <link linkend="yaml-null"><code>yaml.NULL</code></link> - or <link linkend="json-null"><code>json.NULL</code></link> - or <link linkend="msgpack-null"><code>msgpack.NULL</code></link>. + <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>. diff --git a/doc/user/databases.xml b/doc/user/databases.xml index c6194262fb18d26978bb7eba7eede810a2ea28ef..70d7bfcdfd9c44d6ef70bd20fddf4ce6fae4303d 100644 --- a/doc/user/databases.xml +++ b/doc/user/databases.xml @@ -293,7 +293,7 @@ tarantool> <userinput>s = box.schema.space.create('space55', {if_not_exists = tr <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_no, 'NUM'|STR'}</entry><entry>{1, 'NUM'}</entry> + <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> @@ -649,7 +649,7 @@ tarantool> <userinput>box.space.space55.index.primary:rename('secondary')</useri <varlistentry> <term> <emphasis role="lua" xml:id="box.update"> - box.space.<replaceable>space-name</replaceable>:update({<replaceable>key {, operator, field_no, value}...</replaceable>}) + box.space.<replaceable>space-name</replaceable>:update({<replaceable>key {, operator, field_number, value}...</replaceable>}) </emphasis> </term> <listitem> @@ -658,7 +658,7 @@ tarantool> <userinput>box.space.space55.index.primary:rename('secondary')</useri </para> <para> The <code>update</code> function supports operations on fields — - assignment, arithmetic (if the field is unsigned numeric), + 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 @@ -674,18 +674,19 @@ tarantool> <userinput>box.space.space55.index.primary:rename('secondary')</useri <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_no, value}</code> = a group of arguments + <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. - For some operations the field number can be -1, meaning + 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. - Possible operators are: <quote>+</quote> - for addition, <quote>-</quote> for subtraction, - <quote>&</quote> for bitwise AND, - <quote>|</quote> for bitwise OR, <quote>^</quote> - for bitwise exclusive OR (XOR), <quote>:</quote> - for string splice, <quote>!</quote> for insert, - <quote>#</quote> for delete. Thus in the instruction <code>s:update(44, {{'+',1,55},{'=',3,'x'}})</code> the primary-key value is 44, the operators are '+' and '=' @@ -698,7 +699,7 @@ tarantool> <userinput>box.space.space55.index.primary:rename('secondary')</useri Returns: (type = tuple) the updated tuple. </para> <para> - Possible errors: it is illegal to modify a primary-key field. + 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. @@ -1390,7 +1391,7 @@ console.delimiter('')! 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="#fiber.yield">fiber.yield()</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 @@ -2163,7 +2164,7 @@ tarantool> <userinput>tmp</userinput> <varlistentry> <term> - <emphasis role="lua"><replaceable>tuple-value</replaceable>:update(<replaceable>{{format, field_no, value}...}</replaceable>)</emphasis> + <emphasis role="lua"><replaceable>tuple-value</replaceable>:update(<replaceable>{{format, field_number, value}...}</replaceable>)</emphasis> </term> <listitem> <para> @@ -2172,16 +2173,16 @@ tarantool> <userinput>tmp</userinput> <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_no, value}...</replaceable>)</code>, + <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_no</code> indicates the field number to change such as 2 for field number 2, + <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_no</code>, and <code>value</code> - in the section <olink targetptr="box.update"><code>box.space.<replaceable>space-name</replaceable>:update{<replaceable>key, format, {field_no, value}...</replaceable>)</code></olink>. + 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. diff --git a/doc/user/lua-and-packages.xml b/doc/user/lua-and-packages.xml deleted file mode 100644 index 2a5ea7e3200bbdcb0bae5db5bd99d53811cb5c90..0000000000000000000000000000000000000000 --- a/doc/user/lua-and-packages.xml +++ /dev/null @@ -1,33 +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="lua-and-packages"> - -<title>Lua and the Tarantool Lua Packages</title> - -<blockquote> - <para> - <link xlink:href="http://www.lua.org">Lua</link> - is a light-weight, multi-paradigm, embeddable language. - Stored procedures in Lua can be used to implement - data manipulation patterns or data structures. - It is possible to dynamically define, invoke, - alter and drop Lua functions. Lua functions can run - in the background and perform administrative tasks. - </para> -</blockquote> - - -<xi:include href="stored-procedures.xml" /> - - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/preface.xml b/doc/user/preface.xml index 9f56fadea76f5e0cf225fa1cd0e683db05ebfa1d..23e640af369f5f178ac21f19be661b53f2e43842 100644 --- a/doc/user/preface.xml +++ b/doc/user/preface.xml @@ -170,25 +170,18 @@ database"</link>. </para> <para> - Chapter 3 <link linkend="lua-and-packages">"Lua and the Tarantool Lua packages"</link> begins with explanations - about Lua and Tarantool's connection with Lua. Those explanations are - necessary; however, the detailed instructions about each package can be - regarded as reference material, skip over them lightly until their - functionality is needed. - </para> - <para> - Chapter 4 <link linkend="databases">"Databases"</link> is about the Tarantool NoSQL DBMS. + 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 5 <link linkend="replication">"Replication"</link>) will not be necessary. Once again, the + (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 6 <link linkend="server-administration">"Server administration"</link> and Chapter 7 <link linkend="configuration-reference">"Configuration reference"</link> + 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 8 <link linkend="connectors">"Connectors"</link> is strictly for + <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> diff --git a/doc/user/replication.xml b/doc/user/replication.xml index 6ff136b0452322b2797825e84d85bff577bab24f..c03ba8eb04ed7e74f50ca94f11a5aac6bc149b5a 100644 --- a/doc/user/replication.xml +++ b/doc/user/replication.xml @@ -281,10 +281,10 @@ replica for select requests). <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-master/src/tarantool</userinput> +<userinput>~/tarantool/src/tarantool</userinput> <userinput>box.cfg{listen=3301}</userinput> -<userinput>box.schema.user.create('replication', {password = 'password'})</userinput> -<userinput>box.schema.user.grant('replication','read,write','universe')</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> @@ -302,16 +302,16 @@ Now the screen looks like this: (except that UUID values are always different): $ <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-master/src/tarantool</userinput> -~/tarantool-master/src/tarantool: version 1.6.3-1724-g033ed69 +~/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('replication', {password = 'password'})</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('replication','read,write','universe')</userinput> +tarantool> <userinput>box.schema.user.grant('replicator','read,write','universe')</userinput> --- ... tarantool> <userinput>box.space._cluster:select({0},{iterator='GE'})</userinput> @@ -345,8 +345,8 @@ execute these commands:<programlisting> <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-master/src/tarantool</userinput> -<userinput>box.cfg{listen=3302, replication_source='replication:password@localhost:3301'}</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 @@ -381,10 +381,10 @@ tarantool> 2014-10-13 11:20:08.691 [25020] main/101/spawner I> created a repl ~/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-master/src/tarantool</userinput> -/home/username/tarantool-master/src/tarantool: version 1.6.3-1724-g033ed69 +~/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='replication:password@localhost:3301'}</userinput> +tarantool> <userinput>box.cfg{listen=3302, replication_source='replicator:password@localhost:3301'}</userinput> ... ... --- ... @@ -435,10 +435,10 @@ tarantool> <userinput>s:insert{1,'Tuple inserted on Terminal #1'}</userinput> ~/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-master/src/tarantool -/home/username/tarantool-master/src/tarantool: version 1.6.3-1724-g033ed69 +~/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='replication:password@localhost:3301'} +tarantool> box.cfg{listen=3302, replication_source='replicator:password@localhost:3301'} ... ... --- ... @@ -446,7 +446,6 @@ 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'] @@ -633,7 +632,7 @@ even though Terminal #1 is down. </para> <para> On Terminal #1 execute these commands:<programlisting> -<userinput>~/tarantool-master/src/tarantool</userinput> +<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"): @@ -661,8 +660,8 @@ total 8 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-master/src/tarantool</userinput> -/home/username/tarantool-master/src/tarantool: version 1.6.3-515-g0a06cce +~/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> ... ... @@ -712,7 +711,7 @@ to act as a replication source. </para> <para> On Terminal #1, say:<programlisting> -<userinput>box.cfg{replication_source='replication:password@localhost:3302'}</userinput> +<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> @@ -722,7 +721,7 @@ The screen now looks like this: </thead> <tbody> <row><entry><programlisting>... ... -~/tarantool_test_node_1$ ~/tarantool-master/src/tarantool +~/tarantool_test_node_1$ ~/tarantool/src/tarantool ~/tarantool: version 1.6.3-1724-g033ed69 type 'help' for interactive help tarantool> box.cfg{listen=3301} @@ -737,7 +736,7 @@ tarantool> box.space.tester:select({0},{iterator='GE'}) --- - - [1, 'Tuple inserted on Terminal #1'] ... -tarantool> <userinput>box.cfg{replication_source='replication:password@localhost:3302'}</userinput> +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 --- ... diff --git a/doc/user/stored-procedures.xml b/doc/user/stored-procedures.xml deleted file mode 100644 index 8206cc55e0ce99f7837e2bdb4951e82141c971a7..0000000000000000000000000000000000000000 --- a/doc/user/stored-procedures.xml +++ /dev/null @@ -1,3443 +0,0 @@ -<!DOCTYPE section [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<section xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xi="http://www.w3.org/2001/XInclude" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="stored-procedures"> - <title>Writing and running Lua code</title> - - <para> - Procedures can be defined and invoked interactively, for example: - <programlisting><computeroutput>tarantool> <userinput>function f1() return 'hello' end</userinput> ---- -... -tarantool> <userinput>f1()</userinput> ---- -- hello -... -</computeroutput> -</programlisting> - In the above example, the requests are being handled in interactive mode - for evaluation as a chunk of Lua code. - </para> - <para> - Thus, the request "<code>function f1() return 'hello' end</code>" - causes definition of the Lua function which will be identified as f1(). - Then the request "<code>f1()</code>" causes execution of - the function. The function returns a string 'hello', which gets displayed. - </para> - <para> - It's possible to execute any chunk of Lua code, not just invoke functions ... - <programlisting><computeroutput>tarantool> <userinput>1 + 2</userinput> ---- - - 3 -... -tarantool> <userinput>'hello' .. ' world' -- '..' means 'concatenate'</userinput> ---- - - hello world -... -</computeroutput></programlisting> - </para> - <para> - Lua functions could also be called at the time of initialization with a script in a - <olink targetptr="configuration-file">lua-initialization file</olink>. - An example and discussion of such a script will appear later in section - <link linkend="sp-expirationd">expirationd</link>. - </para> - <para> - The initialization script can select and modify data. - </para> - <para> - Another common task to perform in the initialization script - is to start background fibers for data expiration, re-sharding, - or communication with networked peers. - </para> - <para> - Finally, the script can be used to define Lua <olink - targetptr="triggers">triggers</olink> invoked on various events - within the system. - </para> - <note><simpara> - TARANTOOL = A SCRIPT PROCESSOR. Instead of processing scripts with bash or Perl, use tarantool server. - For example, let the first line of a shell script be #!/usr/bin/tarantool. - This will be a - (<link xlink:href="https://en.wikipedia.org/wiki/Shebang_%28Unix%29" xlink:title="wikipedia.org/Shebang">"Hashbang" hint</link>) - that Tarantool will be the script processor. Since Tarantool includes Lua, the file's instructions can be Lua. - </simpara></note> - <para> - There is a single global instance of the Lua interpreter, which is - shared across all connections. Any request from a client - is sent - directly to this interpreter. Any changes of the interpreter - state, including global variable values, have immediate - effect on all client connections. - </para> - <para> - However, each connection uses its own Lua - <emphasis>coroutine</emphasis> — a mechanism akin to a - Tarantool <emphasis>fiber</emphasis>. A coroutine has its - own execution stack and its own set of local variables and - definitions, as described in the - <link xlink:href="http://www.lua.org/pil/6.1.html"> - <emphasis>closure</emphasis> section</link> of the Lua manual. - </para> - <para> - In addition to conventional method invocation, - Lua provides object-oriented syntax. Typically this involves - the format <computeroutput><replaceable>object-specifier</replaceable>:<replaceable>function-name ...</replaceable></computeroutput>, - where object-specifier is acquired as the result of another function invocation, - or is the full <replaceable>library-name.package-name.object-name</replaceable>, - or is the full <replaceable>library-name.package-name['object-name']</replaceable>, - or is the full <replaceable>library-name.package-name[object-numeric-id]</replaceable>. - The following example shows all four forms of object-specifier: -<programlisting> -tarantool> <userinput>s = box.schema.space.create('name_of_space', {id = 33})</userinput> ---- -... -tarantool> <userinput>i = s:create_index('name_of_index', {type = 'tree', parts = {1, 'STR'}})</userinput> ---- -... -tarantool> <userinput>s:insert{'a', 'b', 'c'}</userinput> ---- -- ['a', 'b', 'c'] -... -tarantool> <userinput>box.space.name_of_space:insert{'c', 'd', 'e'}</userinput> ---- -- ['c', 'd', 'e'] -... -tarantool> <userinput>box.space['name_of_space']:insert{'x', 'y', 'z'}</userinput> ---- -- ['x', 'y', 'z'] -... -</programlisting> - </para> - <para> - When a function in Lua terminates with an error, the error - is sent to the client as <olink targetptr="ER_PROC_LUA" /> - return code, along with the original error message. - Similarly, an error which has occurred inside Tarantool (observed on the - client as an error code), when it happens during execution of a - Lua procedure, produces a genuine Lua error: -<programlisting><computeroutput>tarantool> <userinput>function f()error('!') end</userinput> ---- -... -tarantool> <userinput>f()</userinput> -- error: '[string "function f()error(''!'') end"]:1: !' -tarantool> <userinput>s:insert{5}</userinput> ---- -- error: 'Tuple field 1 type does not match one required by operation: - expected STR' -... -tarantool> <userinput>function insert_without_colon(tuple) s:insert(tuple) end</userinput> ---- -... -tarantool> <userinput>pcall(insert_without_colon,{0, 'b', 'c'})</userinput> ---- -- false -- 'Tuple field 1 type does not match one required by operation: expected STR' -tarantool> <userinput>box.space[33]:drop()</userinput> ---- -... -</computeroutput></programlisting> - </para> - -<para> -<bridgehead renderas="sect4">The "Batteries Included" Lua Software Distribution</bridgehead> -Tarantool incorporates open-source -precompiled packages which Tarantool's developers -have tested for compatibility -- the "built-in" packages. -Tarantool specializes in packages which aid -database applications or which Tarantool's own developers -use to make database-related tools. -At the same time. -Tarantool makes it easy to add new Lua packages -from <link xlink:href=" http://luarocks.org/">LuaRocks</link> -- the "downloadable" packages. -</para> - -<para> -The included language processor is <link xlink:href="http://luajit.org/">LuaJIT</link>. -Major "built-in" components are: fibers, -<link xlink:href="http://msgpack.org">MsgPack</link>, -digest, JSON, <link xlink:href="http://en.wikipedia.org/wiki/Yaml">YAML</link>, -<link xlink:href="http://en.wikipedia.org/wiki/Inter-process_communication">IPC</link>, -fio, and box. -</para> - -<para> -<emphasis>LuaJIT</emphasis> is a processor for the entire Lua language. -This differs from the original Lua interpreter from -<link xlink:href="http://www.puc-rio.br/index.html">PontifÃcia Universidade Católica do Rio de Janeiro</link> -("RIO-PUC" <link xlink:href="http://www.lua.org/">Lua</link>) -because the JIT stands for "Just In Time" compiling, that -is, it can compile some Lua code into machine executable form -after a few executions of the code. -The result is that some -loops will run as quickly as an equivalent C program. -Also some precompiled C code can be brought in using -LuaJIT's FFI (<link xlink:href="https://en.wikipedia.org/wiki/Foreign_function_interface">Foreign Function Interface</link>). -Examples for using FFI exist on the Internet, for example -<link xlink:href="https://github.com/tarantool/tarantool/blob/master/src/box/lua/tuple.lua">tuple.lua</link> on the tarantool.org site. -</para> - -<para> -LuaJIT has been compared to competitive implementations -and found to be reliable and efficient, -provided one takes advantage of it where <link xlink:href="http://wiki.luajit.org/Numerical-Computing-Performance-Guide">performance</link> counts. -</para> - - <para> - Apart from increased performance, LuaJIT provides such - features as <link - xlink:href="http://bitop.luajit.org/">bitwise - operations</link> and <link xlink:href="#tonumber64">64-bit integer arithmetic.</link> - </para> - -<para> -<link linkend="sp-box-fiber"><emphasis>Fibers</emphasis></link> are like Lua coroutines, but as <link xlink:href="http://members.chello.nl/~w.couwenberg/fibers.htm">one fiber developer</link> -put it: "The main difference between a coroutine and a fiber -is that a running fiber can be suspended anywhere in a call -chain, regardless of its C and Lua call stack nesting levels." -</para> - -<para> -<link linkend="sp-msgpack"><emphasis>MsgPack</emphasis></link> is a relatively new way to serialize data. -The point of MsgPack is that it can -handle Lua types and C types, with structures and nesting, -without the overhead of an SGML-style markup language. -</para> - -<para> -<link linkend="sp-digest"><emphasis>Digest</emphasis></link> is a cryptography package for CRC32, SHA, and MDA. -Nothing new here -- except that Tarantool has made them into a -package, so that one doesn't have to get each one of these -things individually from the <link xlink:href="http://lua-users.org/wiki/CryptographyStuff">many that are available</link>. -And, since Tarantool is binding with FFI rather than a traditional Lua C -API, the routines should run faster on LuaJIT. -</para> - -<para> -<link linkend="sp-box-cjson"><emphasis>JSON</emphasis></link> is a serialization format which has -become popular in the web world. The package within -Tarantool is derived from <link xlink:href="http://www.kyne.com.au/~mark/software/lua-cjson-manual.html">CJSON</link> -which, according to <link xlink:href="http://lua-users.org/wiki/JsonModules">a survey</link>, -handles Unicode surrogate pairs and is robust when -edge cases come up. -</para> - -<para> -<link linkend="sp-yaml"><emphasis>YAML</emphasis></link> is short for "YAML Ain't a Markup Language". YAML is a -way to show data in human-readable form, without losing -underlying information about typing, arrays, and structures. -</para> - -<para> -<link linkend="sp-fiber-ipc"><emphasis>IPC</emphasis></link> is Inter-Process Communication. -This is useful for implementations of task queues and long polling. -</para> - -<para> -<link linkend="sp-fio"><emphasis>Fio</emphasis></link> is standard file IO, -adapted to work with Tarantool's fibers in a cooperative environment. -</para> - -<para> -<link linkend="sp-tap"><emphasis>Tap</emphasis></link> is a tool to test programs for errors. -</para> - -<para> -<link linkend="sp-box-library"><emphasis>Box</emphasis></link> is the NoSQL DBMS that was developed by Tarantool -and its community. Box's architecture and routines will be the -subject of the next chapter. -</para> - -<para> -<bridgehead renderas="sect4">The Downloadable Packages</bridgehead> -A directory of Lua Addons packages can be found on the <link xlink:href="http://lua-users.org/wiki/LuaAddons">Lua-users</link> wiki. -For a "managed package" system equivalent to Perl's CPAN and Ruby's RubyGems and Python's -Eggs, one gets "rocks" (modules or packages) from <emphasis>LuaRocks</emphasis>. -Either way, the installation requirement can be as simple as saying -require('package-name') -and the effect is a simple Lua table containing -functions and members, superficially like C/Java classes. -</para> - -<para> -There are <link xlink:href="https://rocks.moonscript.org/modules">several hundred LuaRocks packages</link> that are not built-in -but are reasonably easy to obtain by anyone with an Internet -connection. Just as a sampling: ... -<link xlink:href="https://rocks.moonscript.org/modules/kikito/ansicolors">ansicolors</link> for color manipulation, -<link xlink:href="https://rocks.moonscript.org/modules/luarocks/htmlparser">htmlparser</link> for changing HTML text into a tree of elements, -<link xlink:href="https://rocks.moonscript.org/modules/kikito/i18n">i18n</link> an internationalization library, -<link xlink:href="https://rocks.moonscript.org/modules/luarocks/lposix">lposix</link> a POSIX library, -<link xlink:href="https://rocks.moonscript.org/modules/luarocks/lua-spore">lua-Spore</link> a generic ReST client, -<link xlink:href="https://rocks.moonscript.org/modules/luarocks/tekui">TekUI</link> a GUI toolkit. -For example, to bring in the i18n package: install luarocks, say <code>luarocks install i18n</code>, -start Tarantool, and say <code>require('i18n')</code>. -</para> - -<section xml:id="rocks"><title>Installing rocks from tarantool.org</title> -<para> -The Lua rocks that Tarantool supplies are available -on <link xlink:href="http://rocks.tarantool.org">rocks.tarantool.org</link> and can be installed using -the luarocks utilities. Here is an example. -</para> -<para> -Look at rocks.tarantool.org. Notice that one of the -available rocks is expirationd -- Expiration daemon for Tarantool. -</para> -<para> -Create a file named ~/.luarocks/config.lua containing these three lines:<programlisting> -rocks_servers = { - [[http://rocks.tarantool.org/]] -}</programlisting> -Install the expirationd rock with either <programlisting>luarocks --local install expirationd</programlisting> -or, as root user, <programlisting>luarocks install expirationd</programlisting> -Start the tarantool server and make the request:<programlisting>expirationd=require('expirationd')</programlisting> -If there is an error, display the Lua variable -<code>package_path</code> to make sure it is searching along -a path that includes the new expirationd.lua file. -</para> -<para> -If the result is success, which it will be if -nothing unusual has been done when installing -Tarantool or Luarocks, then the new rock is -available henceforward for use in the Tarantool -application server. -</para> - -<para> -The rest of this chapter is a reference that has what's needed for programming and -administration with the built-in packages. -</para> -</section> - -<section xml:id="sp-digest"> - <title>Package <code>digest</code></title> - <para> - A "digest" is a value which is returned by a - - <link xlink:href="https://en.wikipedia.org/wiki/Cryptographic_hash_function">Cryptographic hash function</link> - applied against a string. - Tarantool supports five types of cryptographic hash functions - (<link xlink:href="https://en.wikipedia.org/wiki/Md4">MD4</link>, - <link xlink:href="https://en.wikipedia.org/wiki/Md5">MD5</link>, - <link xlink:href="https://en.wikipedia.org/wiki/Sha-0">SHA-0</link>, - - <link xlink:href="https://en.wikipedia.org/wiki/Sha-1">SHA-1</link>, - <link xlink:href="https://en.wikipedia.org/wiki/Sha-2">SHA-2</link>) - - as well as a checksum function - (<link xlink:href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">CRC32</link>) - and two functions for <link xlink:href="https://en.wikipedia.org/wiki/Base64">base64</link>. - The functions in <code>digest</code> are: - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry>name</entry><entry>effect</entry></row> - </thead> - <tbody> - <row><entry><code>digest.crc32(<replaceable>string</replaceable>)</code></entry><entry> Returns 32-bit checksum made with CRC32. See <link linkend="note-crc32">note</link>.</entry></row> - <row><entry><code>digest.crc32_update(<replaceable>number</replaceable>,<replaceable>string</replaceable>)</code></entry><entry> Returns update of a checksum calculated with CRC32.</entry></row> - <row><entry><code>digest.sha(<replaceable>string</replaceable>)</code></entry><entry> Returns 160-bit digest made with SHA-0. Not recommended.</entry></row> - <row><entry><code>digest.sha_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with sha.</entry></row> - <row><entry><code>digest.sha1(<replaceable>string</replaceable>)</code></entry><entry> Returns 160-bit digest made with SHA-1.</entry></row> - <row><entry><code>digest.sha1_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with sha1.</entry></row> - <row><entry><code>digest.sha224(<replaceable>string</replaceable>)</code></entry><entry> Returns 224-bit digest made with SHA-2.</entry></row> - <row><entry><code>digest.sha224_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with sha224.</entry></row> - <row><entry><code>digest.sha256(<replaceable>string</replaceable>)</code></entry><entry> Returns 256-bit digest made with SHA-2.</entry></row> - <row><entry><code>digest.sha256_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with sha256.</entry></row> - <row><entry><code>digest.sha384(<replaceable>string</replaceable>)</code></entry><entry> Returns 384-bit digest made with SHA-2.</entry></row> - <row><entry><code>digest.sha384_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with sha384.</entry></row> - <row><entry><code>digest.sha512(<replaceable>string</replaceable>)</code></entry><entry> Returns 512-bit digest made with SHA-2.</entry></row> - <row><entry><code>digest.sha512_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with sha512.</entry></row> - <row><entry><code>digest.md4(<replaceable>string</replaceable>)</code></entry><entry> Returns 128-bit digest made with MD4.</entry></row> - <row><entry><code>digest.md4_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with md4.</entry></row> - <row><entry><code>digest.md5(<replaceable>string</replaceable>)</code></entry><entry> Returns 256-bit digest made with MD5.</entry></row> - <row><entry><code>digest.md5_hex(<replaceable>string</replaceable>)</code></entry><entry> Returns hexadecimal of a digest calculated with md5.</entry></row> - <row><entry><code>digest.base64_encode(<replaceable>string</replaceable>)</code></entry><entry> Returns base64 encoding from a regular string.</entry></row> - <row><entry><code>digest.base64_decode(<replaceable>string</replaceable>)</code></entry><entry> Returns a regular string from a base64 encoding.</entry></row> - <row><entry><code>digest.urandom(<replaceable>integer</replaceable>)</code></entry><entry> Returns array of random bytes with length = <replaceable>integer</replaceable>.</entry></row> - <row><entry><code>digest.guava(<replaceable>integer, integer</replaceable>)</code></entry><entry> Returns a number made with consistent hash. See <link linkend="note-guava">note</link>.</entry></row> - </tbody> - </tgroup> - </informaltable> - <note xml:id="note-crc32"><simpara> - <code>digest.crc32(<replaceable>string</replaceable>)</code> uses the - <link xlink:href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Standards_and_common_use"> - CRC-32C (Castagnoli)</link> polynomial value: hexadecimal 11EDC6F41 / decimal 4812730177. - If it is necessary to be compatible with other checksum functions in other programming languages, - ensure that the other functions use the same polynomial value. - For example, in Python, install the crcmod package and say: - <code>import crcmod ... fun = crcmod.mkCrcFun('4812730177') ... fun('string')</code>. - </simpara></note> - <note xml:id="note-guava"><simpara> - <code>digest.guava(<replaceable>integer, integer</replaceable>)</code> uses the - <link xlink:href="https://en.wikipedia.org/wiki/Consistent_hashing"> - Consistent Hashing</link> algorithm of the Google guava library. - The first parameter should be a hash code; the second parameter should be the number of buckets; - the returned value will be an integer between 0 and the number of buckets. - For example, <code>digest.guava(10863919174838991, 11)</code> will return 8. - </simpara></note> - - </para> -<bridgehead renderas="sect4">Example</bridgehead> - <para> - In the following example, the user creates two functions, password_insert() - which inserts a SHA-1 digest of the word "^S^e^c^ret Wordpass" into a tuple set, - and password_check() which requires input of a password.<programlisting> -<prompt>localhost></prompt> <userinput>digest = require('digest')</userinput> -<prompt>localhost></prompt> <userinput>console = require('console'); console.delimiter('!') --this means ignore line feeds until next '!'</userinput> -<prompt>localhost></prompt> <userinput>function password_insert()</userinput> - <prompt>-></prompt> <userinput> box.space.tester:insert{12345,digest.sha1('^S^e^c^ret Wordpass')}</userinput> - <prompt>-></prompt> <userinput> return 'OK'</userinput> - <prompt>-></prompt> <userinput> end!</userinput> ---- -... -<prompt>localhost></prompt> <userinput>function password_check(password)</userinput> - <prompt>-></prompt> <userinput> local t</userinput> - <prompt>-></prompt> <userinput> t=box.space.tester:select{12345}</userinput> - <prompt>-></prompt> <userinput> if (digest.sha1(password)==t[2]) then</userinput> - <prompt>-></prompt> <userinput> print('Password is valid')</userinput> - <prompt>-></prompt> <userinput> else</userinput> - <prompt>-></prompt> <userinput> print('Password is not valid')</userinput> - <prompt>-></prompt> <userinput> end</userinput> - <prompt>-></prompt> <userinput>end!</userinput> ---- -... -<prompt>localhost></prompt> <userinput>password_insert()!</userinput> -Call OK, 1 rows affected -['OK'] -<prompt>localhost></prompt> <userinput>console.delimiter('') -- back to normal: commands end with line feed!</userinput> -</programlisting></para> -<para> - If a later user calls - the password_check() function and enters the wrong password, the result is an - error.<programlisting><prompt>localhost></prompt> <userinput>password_check ('Secret Password')</userinput> ---- -Password is not valid -...</programlisting></para> -</section> - -<section xml:id="sp-box-uuid"> - <title>Package <code>uuid</code></title> - -<para> - A "UUID" is a - <link xlink:href="https://en.wikipedia.org/wiki/Universally_unique_identifier">Universally unique identifier</link>. - If an application requires that a value be unique only within a single computer or - on a single database, then a simple counter is better than a UUID, because getting - a UUID is time-consuming (it requires a - <link xlink:href="https://en.wikipedia.org/wiki/Syscall">syscall</link>). - For clusters of computers, or widely distributed applications, UUIDs are better. -</para> -<para> - The functions that can return a UUID are: <code>uuid()</code>, <code>uuid.bin()</code>, <code>uuid.str()</code>. - The functions that can convert between different types of UUID are: <code>:bin()</code>, <code>:str()</code>, <code>uuid.fromstr()</code>, <code>uuid.frombin()</code>. - The function that can determine whether a UUID is an all-zero value is: <code>:isnil()</code>. -</para> - -<variablelist xml:id="x-uuid" xreflabel="x-uuid"> - - <varlistentry> - <term> - <emphasis role="lua">uuid()</emphasis> - </term> - <listitem> - <para> - Returns: a UUID with type = cdata. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">uuid.bin()</emphasis> - </term> - <listitem> - <para> - Returns: a UUID with type = 16-byte binary string. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">uuid.str()</emphasis> - </term> - <listitem> - <para> - Returns: a UUID with type = 36-byte hexadecimal string. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua"><replaceable>uuid_with_type_cdata</replaceable>:bin([<replaceable>byte-order</replaceable>])</emphasis> - </term> - <listitem> - <para> - Parameters: byte-order can be 'l' (little-endian), 'b' (big-endian), 'h' (endianness depends on host) (default), or 'n' (endianness depends on network). - </para> - <para> - Returns: UUID with type = 16-byte binary string converted from cdata input value. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua"> <replaceable>uuid_with_type_cdata</replaceable>:str()</emphasis> - </term> - <listitem> - <para> - Returns: UUID with type = 36-byte hexadecimal string converted from cdata input value. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua"> uuid.fromstr(<replaceable>uuid_with_type_string</replaceable>)</emphasis> - </term> - <listitem> - <para> - Returns: UUID with type = cdata converted from 36-byte hexadecimal string input value. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">uuid.frombin(<replaceable>uuid_with_type_binary_string</replaceable>)</emphasis> - </term> - <listitem> - <para> - Returns: UUID with type = cdata converted from 16-byte binary string input value. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua"><replaceable>uuid_with_type_cdata</replaceable>:isnil()</emphasis> - </term> - <listitem> - <para> - Returns: true if the value is all zero, otherwise false. - The all-zero UUID value can be expressed as <code>uuid.NULL</code>, or as - uuid.fromstr('00000000-0000-0000-0000-000000000000'). - The comparison with an all-zero value can also be expressed as - <replaceable>uuid_with_type_cdata</replaceable> == uuid.NULL. - </para> - </listitem> - </varlistentry> - -</variablelist> -<para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>uuid = require('uuid')</userinput> ---- -... -tarantool> <userinput>uuid(), uuid.bin(), uuid.str()</userinput> ---- -- 16ffedc8-cbae-4f93-a05e-349f3ab70baa -- !!binary FvG+Vy1MfUC6kIyeM81DYw== -- 67c999d2-5dce-4e58-be16-ac1bcb93160f -... -tarantool> <userinput>uu = uuid()</userinput> ---- -... -tarantool> <userinput>#uu:bin(), #uu:str(), type(uu), uu:isnil()</userinput> ---- -- 16 -- 36 -- cdata -- false -... -</programlisting> -</para> - -</section> - -<section xml:id="sp-box-cjson"> - <title>Package <code>json</code></title> - -<variablelist xml:id="box.cjson" xreflabel="box.cjson"> - <para> - The <code>json</code> package provides JSON manipulation routines. - It is based on the <link xlink:href="http://www.kyne.com.au/~mark/software/lua-cjson.php"> - Lua-CJSON package by Mark Pulford</link>. - - For a complete manual on Lua-CJSON please read <link xlink:href="http://www.kyne.com.au/~mark/software/lua-cjson-manual.html">the official documentation</link>. - </para> - <varlistentry> - <term><emphasis role="lua">json.encode(<replaceable>scalar-value | Lua-table-value</replaceable>)</emphasis></term> - <listitem> - <para> - Convert a Lua object to a JSON string. - </para> - <para> - Parameters: either a scalar value or a Lua table value. - </para> - <para> - Returns: (type = string) the original value reformatted as a JSON string. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>json=require('json')</userinput> ---- -... -tarantool> <userinput>json.encode(123)</userinput> ---- -- '123' -... -tarantool> <userinput>json.encode({123})</userinput> ---- -- '[123]' -... -tarantool> <userinput>json.encode({123, 234, 345})</userinput> ---- -- '[123,234,345]' -... -tarantool> <userinput>json.encode({abc = 234, cde = 345})</userinput> ---- -- '{"cde":345,"abc":234}' -... -tarantool> <userinput>json.encode({hello = {'world'}})</userinput> ---- -- '{"hello":["world"]}' -... -</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua">json.decode(<replaceable>string-value</replaceable>)</emphasis></term> - <listitem> - <para> - Convert a JSON string to a Lua object. - </para> - <para> - Parameters: <code>string-value</code> = a string formatted as JSON. - </para> - <para> - Returns: (type = Lua table) the original contents formatted as a Lua table. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>json=require('json')</userinput> ---- -... -tarantool> <userinput>json.decode('123')</userinput> ---- -- 123 -... -tarantool> <userinput>json.decode('[123, "hello"]')[2]</userinput> ---- -- hello -... -tarantool> <userinput>json.decode('{"hello": "world"}').hello</userinput> ---- -- world -... -</programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua" xml:id="json-null" xreflabel="json-null">json.NULL</emphasis></term> - <listitem> - <para> - Return a value comparable to Lua "nil" which may be useful as a placeholder in a tuple or Lua table. - </para> - <para> - Parameters: none. - </para> - <para> - Returns: the comparable value. - </para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -<prompt>tarantool></prompt> <userinput>-- When nil is assigned to a Lua-table field, the field is null</userinput> -<prompt>tarantool></prompt> <userinput>{nil, 'a', 'b'}</userinput> -- - null - - a - - b -... -<prompt>tarantool></prompt> <userinput> -- When json.NULL is assigned to a Lua-table field, the field is json.NULL</userinput> -<prompt>tarantool></prompt> <userinput>{json.NULL, 'a', 'b'}</userinput> ---- -- - null - - a - - b -... -<prompt>tarantool></prompt> <userinput>-- When json.NULL is assigned to a JSON field, the field is null</userinput> -<prompt>tarantool></prompt> <userinput>json.encode({field2 = json.NULL, field1 = 'a', field3 = 'c'})</userinput> ---- -- '{"field2":null,"field1":"a","field3":"c"}' -...</programlisting> - </listitem> - </varlistentry> -</variablelist> - -</section> - -<section xml:id="sp-yaml"> - <title>Package <code>yaml</code></title> - <para> - The <code>yaml</code> package takes strings in YAML format and decodes them, - or takes a series of non-YAML values and encodes them. - </para> -<variablelist xml:id="yaml"> - <varlistentry> - <term><emphasis role="lua">yaml.encode(<replaceable>scalar-value | Lua-table-value</replaceable>)</emphasis></term> - <listitem> - <para> - Convert a Lua object to a YAML string. - </para> - <para> - Parameters: either a scalar value or a Lua table value. - </para> - <para> - Returns: (type = string) the original value reformatted as a YAML string. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua">yaml.decode(<replaceable>string-value</replaceable>)</emphasis></term> - <listitem> - <para> - Convert a YAML string to a Lua object. - </para> - <para> - Parameters: <code>string-value</code> = a string formatted as YAML. - </para> - <para> - Returns: (type = Lua table) the original contents formatted as a Lua table. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua" xml:id="yaml-null" xreflabel="yaml-null">yaml.NULL</emphasis></term> - <listitem> - <para> - Return a value comparable to Lua "nil" which may be useful as a placeholder in a tuple. - </para> - <para> - Parameters: none. - </para> - <para> - Returns: the comparable value. - </para> - </listitem> - </varlistentry> -</variablelist> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -<prompt>tarantool></prompt> <userinput>yaml = require('yaml')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>y = yaml.encode({'a',1,'b',2})</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>z = yaml.decode(y)</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>z[1],z[2],z[3],z[4]</userinput> ---- -- a -- 1 -- b -- 2 -... -<prompt>tarantool></prompt> <userinput>if yaml.NULL == nil then print('hi') end</userinput> -hi ---- -... -</programlisting> - </para> -</section> - -<section xml:id="sp-msgpack"> - <title>Package <code>msgpack</code></title> - <para> - The <code>msgpack</code> package takes strings in MsgPack format and decodes them, - or takes a series of non-MsgPack values and encodes them. - </para> -<variablelist xml:id="msgpack"> - <varlistentry> - <term><emphasis role="lua">msgpack.encode(<replaceable>scalar-value | Lua-table-value</replaceable>)</emphasis></term> - <listitem> - <para> - Convert a Lua object to a MsgPack string. - </para> - <para> - Parameters: either a scalar value or a Lua table value. - </para> - <para> - Returns: (type = string) the original value reformatted as a MsgPack string. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua">msgpack.decode(<replaceable>string-value</replaceable>[, <replaceable>field-number</replaceable>])</emphasis></term> - <listitem> - <para> - Convert a MsgPack string to a Lua object. - </para> - <para> - Parameters: <code>string-value</code> = a string formatted as MsgPack. - <code>field-number</code> = a number of a particular field to decode. - </para> - <para> - Returns: (type = Lua table) the original contents formatted as a Lua table. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua" xml:id="msgpack-null" xreflabel="msgpack-null">msgpack.NULL</emphasis></term> - <listitem> - <para> - Return a value comparable to Lua "nil" which may be useful as a placeholder in a tuple. - </para> - <para> - Parameters: none. - </para> - <para> - Returns: the comparable value. - </para> - </listitem> - </varlistentry> -</variablelist> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -<prompt>tarantool></prompt> <userinput>msgpack = require('msgpack')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> y = msgpack.encode({'a',1,'b',2})</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> z = msgpack.decode(y)</userinput> ---- -... -<prompt>tarantool></prompt> <userinput> z[1],z[2],z[3],z[4]</userinput> ---- -- a -- 1 -- b -- 2 -... -<prompt>tarantool></prompt> <userinput> box.space.tester:insert{20,msgpack.NULL,20}</userinput> ---- -- [20, null, 20] -... -</programlisting> - </para> -</section> - -<section xml:id="sp-box-fiber"> - <title>Package <code>fiber</code></title> - <para> - The <code>fiber</code> package allows for creating, running and managing <emphasis>fibers</emphasis>. - </para> - <para> - A fiber is a set of instructions which are executed - with cooperative multitasking. Fibers managed by the - fiber package are associated with a user-supplied function - called the <emphasis>fiber function</emphasis>. - - A fiber has three possible states: running, suspended or dead. - When a fiber is created with <code>fiber.create()</code>, it is running. - When a fiber yields control with <code>fiber.sleep()</code>, it is suspended. - When a fiber ends (because the fiber function ends), it is dead. - </para> - <para> - All fibers are part of the fiber registry. - This registry can be searched (<code>fiber.find()</code>) -- via fiber id (fid), which is numeric. - </para> - <para> - A runaway fiber can be stopped with <code><replaceable>fiber_object</replaceable>:cancel()</code>. - However, <code><replaceable>fiber_object</replaceable>:cancel()</code> is advisory — it works - only if the runaway fiber calls <code>fiber.testcancel()</code> - once in a while. Most <code>box.*</code> functions, such as <code>box.space...delete()</code> - or <code>box.space...update()</code>, do call <code>fiber.testcancel()</code> but - <code>box.space...select{}</code> does not. - In practice, a runaway fiber can only become unresponsive - if it does many computations and does not check - whether it's been canceled. -<!-- -In addition to the advisory cancellation, configuration parameter -<code>lua_timeout</code> can be used to cancel runaway Lua -procedures. ---> - </para> - <para> - The other potential problem comes from - fibers which never get scheduled, because they are not subscribed - to any events, or because no relevant events occur. Such morphing fibers - can be killed with <code>fiber.cancel()</code> at any time, - since <code>fiber.cancel()</code> - sends an asynchronous wakeup event to the fiber, - and <code>fiber.testcancel()</code> is checked whenever such an event occurs. - </para> - <para> - Like all Lua objects, dead fibers are - garbage collected. The garbage collector frees pool allocator - memory owned by the fiber, resets all fiber data, and returns - the fiber (now called a fiber carcass) to the fiber pool. - The carcass can be reused when another fiber is created. - </para> -<variablelist xml:id="fiber"> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.create">fiber.create(<replaceable>function</replaceable> [, <replaceable>function-arguments</replaceable>])</emphasis> - </term> - <listitem> - <para> - Create and start a fiber. The fiber is - created and begins to run immediately. - </para> - <para> - Parameters: <code>function</code> = the function to be associated with the fiber, - <code>function-arguments</code> = what will be passed to the function. - </para> - <para> - Returns: (type = userdata) created fiber object. - </para> - <para> - Example: <code>fiber_object = fiber.create(function_name)</code> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.id"><replaceable>fiber_object</replaceable>:id() </emphasis> - </term> - <listitem> - <para> - Parameters: fiber object, for example the fiber object returned by <code>fiber.create</code>. - </para> - <para> - Returns: (type = number) id of the fiber. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.name"><replaceable>fiber_object</replaceable>:name() </emphasis> - </term> - <listitem> - <para> - Parameters: fiber object, for example the fiber object returned by <code>fiber.create</code>. - </para> - <para> - Returns: (type = string) name of the fiber. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="ofiber.name"><replaceable>fiber_object</replaceable>:name(<replaceable>new-name</replaceable>) </emphasis> - </term> - <listitem> - <para> - Change the fiber name. By default the Tarantool server's interactive-mode fiber is named - 'interactive' and new fibers created due to <code>fiber.create</code> are named 'lua'. - Giving fibers distinct names makes it easier to distinguish them when using <code>fiber.info</code>. - </para> - <para> - Parameters: fiber object, for example the fiber object returned by <code>fiber.create</code>; - new-name = (type = string) the new name of the fiber. - </para> - <para> - Returns: nil. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.self">fiber.self() </emphasis> - </term> - <listitem> - <para> - Returns: (type = userdata) fiber object for the currently scheduled fiber. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.find">fiber.find(<replaceable>id</replaceable>) </emphasis> - </term> - <listitem> - <para> - Locate a fiber userdata object by id. - </para> - <para> - Returns: (type = userdata) fiber object for the specified fiber. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.sleep">fiber.sleep(<replaceable>time</replaceable>)</emphasis> - </term> - <listitem> - <para> - Yield control to the scheduler and sleep for the specified number of seconds. - Only the current fiber can be made to sleep. - </para> - <para> - Parameters: <code>time</code> = number of seconds to sleep. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.yield" xreflabel="fiber.yield">fiber.yield() </emphasis> - </term> - <listitem> - <para> - Yield control to the scheduler. Equivalent to <code>fiber.sleep(0)</code>. - </para> - <para> - Parameters: <code>none</code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.ostatus"><replaceable>fiber_object</replaceable>:status()</emphasis> - </term> - <listitem> - <para> - Return the status of the specified fiber. - </para> - <para> - Parameters: <code>fiber_object</code> = the fiber to be checked. - </para> - <para> - Returns: (type = string) the status of <code>fiber</code>. - One of: <quote>dead</quote>, - <quote>suspended</quote>, - or <quote>running</quote>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.status">fiber.status()</emphasis> - </term> - <listitem> - <para> - Return the status of the current fiber. - </para> - <para> - Parameters: none. - </para> - <para> - Returns: (type = string) the status of <code>fiber</code>. - One of: <quote>dead</quote>, - <quote>suspended</quote>, - or <quote>running</quote>. - </para> - </listitem> - </varlistentry> - - - <varlistentry> - <term> - <emphasis role="lua">fiber.info()</emphasis> - </term> - <listitem> - <para> - Return information about all fibers. - </para> - <para> - Returns: (type = table) the name, id, and backtrace of all fibers. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.cancel"><replaceable>fiber_object</replaceable>:cancel()</emphasis> - </term> - <listitem> - <para> - Cancel a <code>fiber</code>. - Running and suspended fibers can be canceled. - After a fiber has been canceled, attempts to operate on it will cause errors, - for example <code><replaceable>fiber_object</replaceable>:id()</code> will cause - "error: the fiber is dead". - </para> - <para> - Parameters: fiber object, for example the fiber returned by <code>fiber.create</code>. - </para> - <para> - Possible errors: cancel is not permitted for the specified fiber object. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.kill">fiber.kill(<replaceable>id</replaceable>) </emphasis> - </term> - <listitem> - <para> - Locate a fiber by its numeric id and cancel it. In - other words, <code>fiber.kill()</code> combines <emphasis - role="lua">fiber.find()</emphasis> and <emphasis - role="lua"><replaceable>fiber_object</replaceable>:cancel()</emphasis>. - </para> - <para> - Parameters: <code>id</code> = the id of the fiber to be canceled. - </para> - <para> - Possible errors: the specified fiber does not exist or cancel is not permitted. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua" xml:id="fiber.testcancel">fiber.testcancel()</emphasis> - </term> - <listitem> - <para> - Check if the current fiber has been canceled and - throw an exception if this is the case. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">fiber.time()</emphasis> - </term> - <listitem> - <para> - Returns: current system time (in seconds since the epoch) as a Lua - number. The time is taken from the event loop - clock, which makes this call very cheap, - but still useful for constructing artificial - tuple keys. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>fiber = require('fiber')</userinput> ---- -... -tarantool> <userinput> fiber.time(), fiber.time()</userinput> ---- - - 1385758759.2591 - - 1385758759.2591 -... -</programlisting> - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - <emphasis role="lua">fiber.time64()</emphasis> - </term> - <listitem> - <para> - Returns: current system time (in microseconds since the epoch) as a 64-bit - integer. The time is taken from the event loop clock. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting>tarantool> <userinput>fiber = require('fiber')</userinput> ---- -... -tarantool> <userinput>fiber.time(), fiber.time64()</userinput> ---- - - 1385758828.9825 - - 1385758828982485 -... -</programlisting> - </para> - </listitem> - </varlistentry> - -</variablelist> - -<para> -<bridgehead renderas="sect4">Example</bridgehead> -Make the function which will be associated with the fiber. -This function contains an infinite loop -("while 0 == 0" is always true). -Each iteration of the loop adds 1 to a global variable -named gvar, then goes to sleep for 2 seconds. -The sleep causes an implicit fiber.yield().<programlisting> -<prompt>tarantool></prompt><userinput> fiber = require('fiber')</userinput> -<prompt>tarantool></prompt><userinput> console = require('console'); console.delimiter('!')</userinput> -<prompt>tarantool></prompt><userinput> function function_x()</userinput> -<prompt> -></prompt><userinput> gvar = 0</userinput> -<prompt> -></prompt><userinput> while 0 == 0 do</userinput> -<prompt> -></prompt><userinput> gvar = gvar + 1</userinput> -<prompt> -></prompt><userinput> fiber.sleep(2)</userinput> -<prompt> -></prompt><userinput> end</userinput> -<prompt> -></prompt><userinput> end!</userinput> ---- -... -<prompt>tarantool></prompt><userinput> console.delimiter('')!</userinput></programlisting> -Make a fiber, associate function_x with the fiber, -and start function_x. It will immediately "detach" -so it will be running independently of the caller. -<programlisting> -<prompt>tarantool></prompt><userinput> fiber_of_x = fiber.create(function_x)</userinput> ---- -...</programlisting> - -Get the id of the fiber (fid), to be used in later displays.<programlisting> -<prompt>tarantool></prompt><userinput> fid = fiber_of_x:id()</userinput> ---- -... -</programlisting> -Pause for a while, while the detached function runs. Then ... -Display the fiber id, the fiber status, and gvar (gvar will have -gone up a bit depending how long the pause lasted). The status is -suspended because the fiber spends almost all its time sleeping or yielding.<programlisting> -<prompt>tarantool></prompt><userinput> print('#',fid,'. ',fiber_of_x:status(),'. gvar=',gvar)</userinput> -# 102 . suspended . gvar= 399 ---- -... -</programlisting> -Pause for a while, while the detached function runs. Then ... -Cancel the fiber. Then, once again ... -Display the fiber id, the fiber status, and gvar (gvar will have -gone up a bit more depending how long the pause lasted). This time -the status is dead because the cancel worked.<programlisting> -<prompt>tarantool></prompt><userinput> fiber_of_x:cancel()</userinput> -... fiber `lua' has been cancelled -... fiber `lua': exiting ---- -... -<prompt>tarantool></prompt><userinput> print('#',fid,'. ',fiber_of_x:status(),'. gvar=',gvar)</userinput> -# 102 . dead . gvar= 421 ---- -...</programlisting> -</para> - -</section> - -<section xml:id="sp-fiber-ipc"> - <title>Package <code>fiber-IPC</code> — inter-process communication</title> - <para> - The <code>fiber-IPC</code> package allows sending and receiving messages between - different processes. The words "different processes" in this context mean - different connections, different sessions, or different fibers. - </para> - <para> - Call <code>fiber.channel()</code> to allocate space and get a channel object, which will be - called <code>channel</code> for examples in this section. - Call the other fiber-IPC routines, via <code>channel</code>, to send messages, receive messages, or check ipc status. - Message exchange is synchronous. - The channel is garbage collected when no one is using it, as with any - other Lua object. - Use object-oriented syntax, for example <code>channel:put(message)</code> - rather than <code>fiber.channel.put(message)</code>. - </para> -<variablelist xml:id="fiber.ipc"> - <para> - </para> - <varlistentry> - <term><emphasis role="lua">fiber.channel(<replaceable>capacity-number</replaceable>)</emphasis></term> - <listitem> - <para> - Create a new communication channel. - </para> - <para> - Parameters: <code>capacity-number</code> = - a positive integer as great as the maximum number of slots - (spaces for get or put or broadcast messages) - that might be pending at any given time. - </para> - <para> - Returns: new channel. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:put(<replaceable>message[, timeout]</replaceable>)</emphasis></term> - <listitem> - <para> - Send a message using a channel. If the channel is full, - <code>channel:put()</code> - blocks until there is a free slot in the channel. - </para> - <para> - Parameters: <code>message</code>, <code>timeout</code>. - </para> - <para> - Returns: (type = boolean) If <code>timeout</code> is provided, - and the channel doesn't become empty for the duration - of the timeout, - <code>channel:put()</code> - returns false. Otherwise it returns true. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:close()</emphasis></term> - <listitem> - <para> - Close the channel. All waiters in the channel will be - woken up. All following <code>channel:put()</code> - or <code>channel:get()</code> operations will return - an error (nil). - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:get(<replaceable>[timeout]</replaceable>)</emphasis></term> - <listitem> - <para> - Fetch a message from a channel. If the channel is empty, - <code>channel:get()</code> - blocks until there is a message. - </para> - <para> - Parameters: <code>timeout</code>. - </para> - <para> - Returns: the value placed on the channel by an earlier <code>channel:put()</code> or <code>channel:broadcast()</code>. - </para> - <para> - Possible errors: If <code>timeout</code> is provided, - and there are no new messages for the duration - of the timeout, - <code>channel:get()</code> - returns error. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:broadcast(<replaceable>message</replaceable>)</emphasis></term> - <listitem> - <para> - If the channel is empty, <code>channel:broadcast()</code> is equivalent to - <code>channel:put()</code>. - Otherwise, <code>channel:broadcast()</code> sends the message to all readers of the - channel. - </para> - <para> - Parameters: <code>message</code>. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:is_empty()</emphasis></term> - <listitem> - <para> - Check whether the specified channel is empty (has no messages). - </para> - <para> - Returns: (type = boolean) true if the specified channel is empty. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:count()</emphasis></term> - <listitem> - <para> - Find out how many messages are on the channel. The answer is 0 if the channel is empty. - </para> - <para> - Returns: (type = number) the number of messages. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:is_full()</emphasis></term> - <listitem> - <para> - Check whether the specified channel is full. - </para> - <para> - Returns: (type = boolean) true if the specified channel is full (has no room for a new message). - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:has_readers()</emphasis></term> - <listitem> - <para> - Check whether the specified channel is empty and has readers waiting - for a message (because they have issued <code>channel:get()</code> and then - blocked). - </para> - <para> - Returns: (type = boolean) true if blocked users are waiting. Otherwise false. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:has_writers()</emphasis></term> - <listitem> - <para> - Check whether the specified channel is full and has writers waiting - (because they have issued <code>channel:put()</code> and then blocked - due to lack of room). - </para> - <para> - Returns: (type = boolean) true if blocked users are waiting. Otherwise false. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><emphasis role="lua"><replaceable>channel</replaceable>:is_closed()</emphasis></term> - <listitem> - <simpara> - Returns: (type = boolean) true if the specified channel is already - closed. - Otherwise false. - </simpara> - </listitem> - </varlistentry> -</variablelist> -<para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting><userinput> - -fiber = require('fiber') -channel = fiber.channel(10) -function consumer_fiber() - while true do - local task = channel:get() - ... - end -end - -function consumer2_fiber() - while true do - local task = channel:get(10) -- 10 seconds - if task ~= nil then - ... - else - ... -- timeout - end - end -end - -function producer_fiber() - while true do - task = box.space...:select{...} - ... - if channel:is_empty() then - # channel is empty - end - - if channel:is_full() then - # channel is full - end - - ... - if channel:has_readers() then - # there are some fibers that are waiting for data - end - ... - - if channel:has_writers() then - # there are some fibers that are waiting for readers - end - channel:put(task) - end -end - -function producer2_fiber() - while true do - task = box.space...select{...} - - if channel:put(task, 10) then -- 10 seconds - ... - else - ... -- timeout - end - end -end -</userinput></programlisting> -</para> -</section> - -<section xml:id="sp-box-session"> - <title>Package <code>box.session</code></title> - <para> - The <code>box.session</code> package allows querying the session state, - writing to a session-specific temporary Lua table, or setting up triggers - which will fire when a session starts or ends. - A <emphasis>session</emphasis> is an object associated with each client connection. - </para> -<variablelist> - <varlistentry> - <term> - <emphasis role="lua">box.session.id() </emphasis> - </term> - <listitem> - <para> - Returns: (type = number) the unique identifier - (ID) for the current session. The result can be 0 meaning - there is no session. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.session.exists(<replaceable>id</replaceable>) </emphasis> - </term> - <listitem> - <para> - Returns: (type = number) 1 if the session exists, - 0 if the session does not exist. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.session.peer(<replaceable>id</replaceable>) </emphasis> - </term> - <listitem> - <para> - Parameters: <code>id</code> = the unique identifier of the session. - </para> - <para> - Returns: (type = string) If the specified session exists, the host - address and port of the session peer, for example "127.0.0.1:55457". - If the specified session does not exist, "0.0.0.0:0". The command is executed on the server, - so the "local name" is the server's host and administrative port, - and the "peer name" is the client's host and port. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">box.session.storage</emphasis> - </term> - <listitem> - <para> - A Lua table that can hold arbitrary - unordered session-specific names and values, which will last until - the session ends. - </para> - </listitem> - </varlistentry> -</variablelist> - -<para> -<bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt><userinput> box.session.peer(session.id())</userinput> ---- - - 127.0.0.1:45129 -... -<prompt>tarantool></prompt><userinput> box.session.storage.random_memorandum = "Don't forget the eggs."</userinput> ---- -... -<prompt>tarantool></prompt><userinput> box.session.storage.radius_of_mars = 3396</userinput> ---- -... - -<prompt>tarantool></prompt><userinput> m = ''</userinput> ---- -... -<prompt>tarantool></prompt><userinput> for k, v in pairs(box.session.storage) do m = m .. k .. '=' .. v .. ' ' end</userinput> ---- -... -<prompt>tarantool></prompt><userinput> m</userinput> ---- -- 'radius_of_mars=3396 random_memorandum=Don''t forget the eggs. ' -...</programlisting> -</para> - - <para> - See <olink targetptr="sp-box-session-triggers">the section "Triggers on connect and disconnect"</olink> - for instructions about defining triggers for connect and disconnect events - with <code>box.session.on_connect()</code> and <code>box.session.on_disconnect()</code>. - See <link linkend="authentication">the section "Authentication and access control"</link> - for instructions about <code>box.session</code> functions that affect user identification and security. - </para> -</section> - -<section xml:id="sp-box-socket"> - <title>Package <code>socket</code> — TCP and UDP sockets</title> -<variablelist xml:id="socket"> - <para> - The <code>socket</code> package allows exchanging data via BSD sockets - with a local or remote host in connection-oriented (TCP) or datagram-oriented (UDP) mode. - Semantics of the calls in the <code>socket</code> API closely follow - semantics of the corresponding POSIX calls. Function names - and signatures are mostly compatible with - <link xlink:href="http://w3.impa.br/~diego/software/luasocket/">luasocket</link>. - </para> - <para> - The functions for setting up and connecting are <code>socket</code>, <code>sysconnect</code>, <code>tcp_connect</code>. - The functions for sending data are <code>send</code>, <code>sendto</code>, <code>write</code>, <code>syswrite</code>. - The functions for receiving data are <code>recv</code>, <code>recvfrom</code>, <code>read</code>. - The functions for waiting before sending/receiving data are <code>wait</code>, <code>readable</code>, <code>writable</code>. - The functions for setting flags are <code>nonblock</code>, <code>setsockopt</code>. - The functions for stopping and disconnecting are <code>shutdown</code>, <code>close</code>. - The functions for error checking are <code>errno</code>, <code>error</code>. - </para> - <para> - <table> - <title xml:id="socket-functions">Socket functions: Names, Purposes</title> - <tgroup cols="2" align="left" colsep="1" rowsep="1"> - <thead> - <row><entry>Name</entry><entry>Purpose</entry></row> - </thead> - <tbody> - <row><entry>socket</entry><entry>setup</entry></row> - <row><entry><link linkend="socket-sysconnect">sysconnect</link></entry><entry>setup</entry></row> - <row><entry><link linkend="socket-tcpconnect">tcp_connect</link></entry><entry>setup</entry></row> - <row><entry><link linkend="socket-send">send</link></entry><entry>sending</entry></row> - <row><entry><link linkend="socket-sendto">sendto</link></entry><entry>sending</entry></row> - <row><entry><link linkend="socket-send">write</link></entry><entry>sending</entry></row> - <row><entry><link linkend="socket-syswrite">syswrite</link></entry><entry>sending</entry></row> - <row><entry><link linkend="socket-recv">recv</link></entry><entry>receiving</entry></row> - <row><entry><link linkend="socket-recvfrom">recvfrom</link></entry><entry>receiving</entry></row> - <row><entry><link linkend="socket-read">read</link></entry><entry>receiving</entry></row> - <row><entry><link linkend="socket-nonblock">nonblock</link></entry><entry>flag setting </entry></row> - <row><entry><link linkend="socket-setsockopt">setsockopt</link></entry><entry>flag setting </entry></row> - <row><entry><link linkend="socket-linger">linger</link></entry><entry>flag setting</entry></row> - <row><entry><link linkend="socket-listen">listen</link></entry><entry>client/server</entry></row> - <row><entry><link linkend="socket-accept">accept</link></entry><entry>client/server</entry></row> - <row><entry><link linkend="socket-shutdown">shutdown</link></entry><entry>teardown</entry></row> - <row><entry><link linkend="socket-close">close</link></entry><entry>teardown</entry></row> - <row><entry><link linkend="socket-error">errno</link></entry><entry>serror checking</entry></row> - <row><entry><link linkend="socket-error">error</link></entry><entry>error checking</entry></row> - <row><entry><link linkend="socket-getaddrinfo">getaddrinfo</link></entry><entry>information</entry></row> - <row><entry><link linkend="socket-getsockopt">getsockopt</link></entry><entry>information</entry></row> - <row><entry><link linkend="socket-peer">peer</link></entry><entry>information</entry></row> - <row><entry><link linkend="socket-name">name</link></entry><entry>information</entry></row> - </tbody> - </tgroup> - </table> - </para> - <para> - Typically a socket session will begin with the setup functions, - will set one or more flags, will have a loop with sending and receiving functions, - will end with the teardown functions -- as an example at the end of this section will show. - Throughout, there may be error-checking and waiting functions for synchronization. - Some functions may "block" if a non-default option flag is set, - therefore the fiber that they are in will yield so that other processes may take - over, as is the norm for cooperative multitasking. - </para> - <para> - For all examples in this section the socket name will be <code>sock</code> - and the function invocations will look like <code>sock:<replaceable>function_name</replaceable>(...)</code>. - </para> - - <varlistentry> - <term xml:id="socket-socket" xreflabel="socket-socket"><emphasis role="lua">socket(<replaceable>domain</replaceable>, <replaceable>type</replaceable>, <replaceable>protocol</replaceable>)</emphasis></term> - <listitem> - <para> - Create a new TCP or UDP socket. - The argument values are the same as in the <link xlink:href="http://man7.org/linux/man-pages/man2/socket.2.html">Linux man page</link>. - </para> - <para> - Returns: (type = userdata) a new socket, or <code>nil</code>. - </para> - <para> - Example: <code>socket = require('socket'); sock = socket('AF_INET', 'SOCK_STREAM', 'tcp')</code> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-sysconnect" xreflabel="socket-sysconnect"><emphasis role="lua"><replaceable>sock</replaceable>:sysconnect(<replaceable>host, port</replaceable>)</emphasis></term> - <listitem> - <para> - Connect a socket to a remote host. - The argument values are the same as in the <link xlink:href="http://man7.org/linux/man-pages/man2/connect.2.html">Linux man page</link>. - The host must be an IP address. - </para> - <para> - Parameters: Either: <code>host</code> -- a string representation of an IPv4 address or an IPv6 address; <code>port</code> -- a number. - Or: <code>host</code> -- a string containing "unix/"; <code>port</code> -- a string containing a path to a unix socket. - Or: <code>host</code> -- a number, 0 (zero), meaning "all local interfaces"; <code>port</code> -- a number. - If a port number is 0 (zero), the socket will be bound to a random local port. - </para> - <para> - Returns: (type = userdata) a connected socket, if no error. - </para> - <para> - Example: <code>sock:sysconnect('127.0.0.1', 80)</code> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-tcpconnect" xreflabel="socket-tcpconnect"><emphasis role="lua">socket.tcp_connect(<replaceable>host, port</replaceable>)</emphasis></term> - <listitem> - <para> - Connect a socket to a remote host. - </para> - <para> - Parameters: <code>host</code>, <code>port</code>. The host may be a URL rather than an IP address. - </para> - <para> - Returns: (type = userdata) a connected socket, if no error. - </para> - <para> - Example: <code>socket.tcp_connect('tarantool.org', 80)</code> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-send" xreflabel="socket-send"><emphasis role="lua"><replaceable>sock</replaceable>:send(<replaceable>data</replaceable>)</emphasis></term> - <listitem> - <para> - Send data over a connected socket. - </para> - <para> - Parameters: <code>data</code> (type = string). - </para> - <para> - Returns: (type = boolean) true if success, false if error. - </para> - <para> - Notes: The function <code>sock:write(...)</code> has the same parameters and same effect. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-syswrite" xreflabel="socket-syswrite"><emphasis role="lua"><replaceable>sock</replaceable>:syswrite(<replaceable>size</replaceable>)</emphasis></term> - <listitem> - <para> - Write as much as possible data to the socket buffer if non-blocking. - Rarely used. For details see <link xlink:href="https://github.com/tarantool/tarantool/wiki/sockets%201.6">this description</link>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-recv" xreflabel="socket-recv"><emphasis role="lua">sock:recv(<replaceable>size</replaceable>)</emphasis></term> - <listitem> - <para> - Read <code>size</code> bytes from a connected socket. - An internal read-ahead buffer is used to reduce the cost - of this call. - </para> - <para> - Parameters: <code>size</code>(type = integer). - </para> - <para> - Returns: (type = string) a string of the requested length on success. - On error, returns an empty string, followed - by <code>status, errno, errstr</code>. - In case the writing side has closed its end, returns the remainder - read from the socket (possibly an empty string), - followed by <code>"eof"</code> status. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-read" xreflabel="socket-read"> - <emphasis role="lua"><replaceable>sock</replaceable>:read(<replaceable>limit</replaceable> [, <replaceable>timeout</replaceable>])</emphasis> - or <emphasis role="lua"><replaceable>sock</replaceable>:read(<replaceable>delimiter</replaceable> [, <replaceable>timeout</replaceable>])</emphasis> - or <emphasis role="lua"><replaceable>sock</replaceable>:read({limit=<replaceable>limit</replaceable>} [, <replaceable>timeout</replaceable>])</emphasis> - or <emphasis role="lua"><replaceable>sock</replaceable>:read({delimiter=<replaceable>delimiter</replaceable>} [, <replaceable>timeout</replaceable>])</emphasis> - or <emphasis role="lua"><replaceable>sock</replaceable>:read({limit=<replaceable>limit</replaceable>, delimiter=<replaceable>delimiter</replaceable>} [, <replaceable>timeout</replaceable>])</emphasis> - </term> - <listitem> - <para> - Read from a connected socket until some condition is true, and return the bytes that were read. - </para> - <para> - Parameters: <code>limit</code> (type = integer) — maximum number of bytes to read for example 50 means "stop after 50 bytes", - <code>delimiter</code> (type = string) — separator or <link xlink:href="http://www.lua.org/pil/20.2.html">Lua pattern</link> for example '[0-9]' means "stop after a digit", - <code>timeout</code> (type = number) — maximum number of seconds to wait for example 50 means "stop after 50 seconds". - Reading goes on until <code>limit</code> bytes have been read, - or a delimiter has been read, or a timeout has expired. - </para> - <para> - Returns: - (type = string) an empty string if there is nothing more to read, - or a nil value if error, - or a string up to <code>limit</code> bytes long, - which may include the bytes that matched the <code>delimiter</code> expression. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-sysread" xreflabel="socket-sysread"><emphasis role="lua"><replaceable>sock</replaceable>:sysread(<replaceable>size</replaceable>)</emphasis></term> - <listitem> - <para> - Return all available data from the socket buffer if non-blocking. - Rarely used. For details see <link xlink:href="https://github.com/tarantool/tarantool/wiki/sockets%201.6">this description</link>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-bind" xreflabel="socket-bind"><emphasis role="lua"><replaceable>sock</replaceable>:bind(<replaceable>host</replaceable>[, <replaceable>port</replaceable>])</emphasis></term> - <listitem> - <para> - Bind a socket to the given host/port. - A UDP socket after binding can be used - to receive data (see <code><link linkend="socket-recvfrom">recvfrom()</link></code>). A TCP socket - can be used to accept new connections, after it has - been put in listen mode. - </para> - <para> - Parameters: <code>host</code>, <code>port</code>. - </para> - <para> - Returns: (type = userdata) a socket object on success, <code>nil, status, errno, errstr</code> on error. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-listen" xreflabel="socket-listen"><emphasis role="lua"><replaceable>sock</replaceable>:listen(backlog)</emphasis></term> - <listitem> - <para> - Start listening for incoming connections. - </para> - <para> - On Linux the listen <code>backlog</code> - backlog may be from <filename>/proc/sys/net/core/somaxconn</filename>, - on BSD the backlog may be <constant>SOMAXCONN</constant>. - </para> - <para> - Returns: (type = boolean) true for success, false for error. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-accept" xreflabel="socket-accept"><emphasis role="lua"><replaceable>sock</replaceable>:accept()</emphasis></term> - <listitem> - <para> - Accept a new client connection and create a new connected socket. - It is good practice to set the socket's blocking mode explicitly after accepting. - </para> - <para> - Returns: new socket if success, null if error. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-sendto" xreflabel="socket-sendto"><emphasis role="lua"><replaceable>sock</replaceable>:sendto(<replaceable>host, port, data</replaceable>)</emphasis></term> - <listitem> - <para> - Send a message on a UDP socket to a specified host. - </para> - <para> - Parameters: <code>host</code>, <code>port</code>, <code>data</code> (type = string), . - </para> - <para> - Returns: if successful: (type = integer) the number of bytes sent. - </para> - <para> - Returns: if not successful: status, errno, errstr. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-recvfrom" xreflabel="socket-recvfrom"><emphasis role="lua"><replaceable>sock</replaceable>:recvfrom(<replaceable>limit</replaceable>)</emphasis></term> - <listitem> - <para> - Receive a message on a UDP socket. - </para> - <para> - Parameters: <code>limit</code> (type = integer). - </para> - <para> - Returns: if successful: (type = string) message, (type = table) a table containing "host" and "family" and "port" fields. - </para> - <para> - Returns: if not successful: status, errno, errstr. - </para> - <para> - Example: after <code>message_content, message_sender = recvfrom(1)</code> the value of <code>message_content</code> - might be a string containing 'X' and the value of <code>message_sender</code> might be a table containing - message_sender.host = '18.44.0.1', message_sender.family = 'AF_INET', message_sender.port = 43065. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-shutdown" xreflabel="socket-shutdown"><emphasis role="lua"><replaceable>sock</replaceable>:shutdown(<replaceable>how</replaceable>)</emphasis></term> - <listitem> - <para> - Shutdown a reading end, a writing end, or both ends of a socket. - </para> - <para> - Parameters: <code>how</code> = socket.SHUT_RD, socket.SHUT_WR, - or socket.SHUT_RDWR. - </para> - <para> - Returns: true or false. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-close" xreflabel="socket-close"><emphasis role="lua"><replaceable>sock</replaceable>:close()</emphasis></term> - <listitem> - <para> - Close (destroy) a socket. - A closed socket should not be used any more. - A socket is closed automatically - when its userdata is garbage collected by Lua. - </para> - <para> - Returns: (type = boolean) true on success, false on error. - For example, if sock is already closed, sock:close() returns false. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-error" xreflabel="socket-error"><emphasis role="lua"><replaceable>sock</replaceable>:error() and <replaceable>sock</replaceable>:errno()</emphasis></term> - <listitem> - <para> - Retrieve information about the last error that occurred on a socket, if any. - Errors do not cause throwing of exceptions so these functions are usually necessary. - </para> - <para> - Returns:(type = number) result for sock:errno(), (type = string) result for sock:error(). - If there is no error, then sock:errno() will return 0 and sock:error() will return null. - </para> - <para> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-setsockopt" xreflabel="socket-setsockopt"><emphasis role="lua"><replaceable>sock</replaceable>:setsockopt(<replaceable>level, name, value</replaceable>)</emphasis></term> - <listitem> - <para> - Set socket flags. The argument values are the same as in the <link xlink:href="http://man7.org/linux/man-pages/man2/setsockopt.2.html">Linux man page</link>. - The ones that Tarantool accepts are - SO_ACCEPTCONN, SO_BINDTODEVICE, SO_BROADCAST, SO_BSDCOMPAT, SO_DEBUG, - SO_DOMAIN, SO_ERROR, SO_DONTROUTE, SO_KEEPALIVE, SO_MARK, SO_OOBINLINE, - SO_PASSCRED, SO_PEERCRED, SO_PRIORITY, SO_PROTOCOL, SO_RCVBUF, SO_RCVBUFFORCE, - SO_RCVLOWAT, SO_SNDLOWAT, SO_RCVTIMEO, SO_SNDTIMEO, SO_REUSEADDR, SO_SNDBUF, - SO_SNDBUFFORCE, SO_TIMESTAMP, and SO_TYPE. - Setting SO_LINGER is done with sock:linger(active), see below. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-getsockopt" xreflabel="socket-getsockopt"><emphasis role="lua"><replaceable>sock</replaceable>:getsockopt(<replaceable>level, name</replaceable>)</emphasis></term> - <listitem> - <para> - Get socket flags. For a list of possible flags see description of the previous function, - sock:setsockopt(). - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-linger" xreflabel="socket-linger"><emphasis role="lua"><replaceable>sock</replaceable>:linger([<replaceable>active</replaceable>])</emphasis></term> - <listitem> - <para> - Set or clear the SO_LINGER flag. For a description of the flag, see <link xlink:href="http://man7.org/linux/man-pages/man1/loginctl.1.html">Linux man page</link>. - </para> - <para> - Parameters: <code>active</code>. - </para> - <para> - Returns: new active and timeout values. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-nonblock" xreflabel="socket-nonblock"><emphasis role="lua"><replaceable>sock</replaceable>:nonblock([<replaceable>flag</replaceable>])</emphasis></term> - <listitem> - <para> - <code>sock:nonblock()</code> returns the current flag value. - <code>sock:nonblock(true)</code> sets the flag to false and returns false. - <code>sock:nonblock(true)</code> sets the flag to true and returns true. - This function may be useful before invoking a function which might otherwise block indefinitely. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-readable" xreflabel="socket-readable"><emphasis role="lua"><replaceable>sock</replaceable>:readable([<replaceable>timeout</replaceable>])</emphasis>, <emphasis>sock:writable([<replaceable>timeout</replaceable>])</emphasis>, <emphasis>sock:wait([<replaceable>timeout</replaceable>])</emphasis></term> - <listitem> - <para> - <code>sock:readable()</code> waits until something is readable, or until a timeout value expires. - <code>sock:writable()</code> waits until something is writable, or until a timeout value expires. - <code>sock:wait()</code> waits until something is either readable or writable, or until a timeout value expires. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-name" xreflabel="socket-name"><emphasis role="lua"><replaceable>sock</replaceable>:name()</emphasis></term> - <listitem> - <para> - The <code>sock:name()</code> function is used to get information about the near side of the connection. - If a socket was bound to xyz.com:45, then <code>sock:name</code> will return information about [host:xyz.com, port:45]. - The equivalent POSIX function is <code>getsockname()</code>. - </para> - <para> - Returns: A table containing these fields: "host", "family", "type", "protocol", "port". - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-peer" xreflabel="socket-peer"><emphasis role="lua"><replaceable>sock</replaceable>:peer()</emphasis></term> - <listitem> - <para> - The <code>sock:peer()</code> function is used to get information about the far side of a connection. - If a TCP connection has been made to a distant host tarantool.org:80, <code>sock:peer</code> will return information about [host:tarantool.org, port:80]. - The equivalent POSIX function is <code>getpeername()</code>. - </para> - <para> - Returns: A table containing these fields: "host", "family", "type", "protocol", "port". - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-getaddrinfo" xreflabel="socket-getaddrinfo"><emphasis role="lua">socket.getaddrinfo(<replaceable>host</replaceable>, <replaceable>type</replaceable> [, <replaceable>{option-list}</replaceable>)</emphasis></term> - <listitem> - <para> - The <code>socket.getaddrinfo()</code> function is useful for finding - information about a remote site so that the correct arguments for - <code>sock:sysconnect()</code> can be passed. - </para> - <para> - Returns: An array containing "host:", "family", "type:", "protocol:", and "port:" fields. - </para> - <para> - Example: <code>socket.getaddrinfo('tarantool.org', 'http')</code> will return variable information - such as "- - host: 188.93.56.70, family: AF_INET, type: SOCK_STREAM, protocol: tcp, port: 80". - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term xml:id="socket-tcp_server" xreflabel="socket-tcp_server"><emphasis role="lua">socket.tcp_server(<replaceable>host</replaceable>, <replaceable>port</replaceable>, <replaceable>handler-function</replaceable>)</emphasis></term> - <listitem> - <para> - The <code>socket.tcp_server()</code> function makes Tarantool act as a server - that can accept connections. - Usually the same objective is accomplished with <code>box.cfg{listen=...)</code>. - </para> - <para> - Example: <code>socket.tcp_server('localhost', 3302, function () end)</code>. - </para> - </listitem> - </varlistentry> - -</variablelist> - - - <bridgehead renderas="sect4">Socket example #1: use of a TCP socket over the Internet</bridgehead> - <para> - In this example a connection is made over the internet between the Tarantool server - and <link xlink:href="http://tarantool.org">tarantool.org</link>, - then an HTTP "head" message is sent, and a response is received: "HTTP/1.1 200 OK". - This is not a useful way to communicate with this particular site, - but shows that the system works. -<programlisting> -<prompt>tarantool></prompt> <userinput>socket = require('socket')</userinput> ---- -... - -<prompt>tarantool></prompt> <userinput>sock = socket.tcp_connect('tarantool.org', 80)</userinput> ---- -... - -<prompt>tarantool></prompt> <userinput>type(sock)</userinput> ---- -- table -... - -<prompt>tarantool></prompt> <userinput>sock:error()</userinput> ---- -- null -... - -<prompt>tarantool></prompt> <userinput>sock:send("HEAD / HTTP/1.0\r\nHost: tarantool.org\r\n\r\n")</userinput> ---- -- true -... - -<prompt>tarantool></prompt> <userinput>sock:read(17)</userinput> ---- -- "HTTP/1.1 200 OK\r\n" -... - -<prompt>tarantool></prompt> <userinput>sock:close()</userinput> ---- -- true -... -</programlisting> -</para> - -<bridgehead renderas="sect4">Socket example #2: Example showing use of a UDP socket on localhost</bridgehead> - <para> -Here is an example with datagrams. -Set up two connections on 127.0.0.1 (localhost): sock_1 and sock_2. -Using sock_2, send a message to sock_1. -Using sock_1, receive a message. -Display the received message. -Close both connections. -This is not a useful way for a computer to communicate with itself, -but shows that the system works. -<programlisting> -<prompt>tarantool></prompt> <userinput>socket = require('socket')</userinput> ---- -... - -<prompt>tarantool></prompt> <userinput> sock_1 = socket('AF_INET', 'SOCK_DGRAM', 'udp')</userinput> ---- -... - -<prompt>tarantool></prompt> <userinput> sock_1:bind('127.0.0.1')</userinput> ---- -- true -... - -<prompt>tarantool></prompt> <userinput> sock_2 = socket('AF_INET', 'SOCK_DGRAM', 'udp')</userinput> ---- -... - -<prompt>tarantool></prompt> <userinput> sock_2:sendto('127.0.0.1', sock_1:name().port,'X')</userinput> ---- -- true -... - -<prompt>tarantool></prompt> <userinput> message = sock_1:recvfrom()</userinput> ---- -... - -<prompt>tarantool></prompt> <userinput> message</userinput> ---- -- X -... - -<prompt>tarantool></prompt> <userinput> sock_1:close()</userinput> ---- -- true -... - -<prompt>tarantool></prompt> <userinput> sock_2:close()</userinput> ---- -- true -... -</programlisting> - -</para> - -</section> - -<section xml:id="sp-fio"> -<title>package <code>fio -- Cooperative File I/O</code></title> - <para> - Tarantool supports file input/output with an API that is similar to POSIX syscalls. - All operations are performed asynchronously. - Multiple fibers can access the same file simultaneously. - </para> - <variablelist> - - <varlistentry> - <term><emphasis role="lua">fio.pathjoin(<replaceable>partial-string [, partial-string ...]</replaceable>)</emphasis></term> - <listitem> - <para> - Concatenate partial strings, separated by '/', to form a path name. - </para> - <para> - Parameters: (type = string) one or more strings to be concatenated. - </para> - <para> - Returns: path name - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.pathjoin('/etc', 'default', 'myfile')</userinput> ---- -- /etc/default/myfile -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.basename(<replaceable>path-name</replaceable>[, <replaceable>suffix</replaceable>])</emphasis></term> - <listitem> - <para> - Given a full path name, remove all but the final part (the file name). - Also remove the suffix, if it is passed. - </para> - <para> - Parameters: (type = string) path name, (type = string) suffix. - </para> - <para> - Returns: file name. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.basename('/path/to/my.lua', '.lua')</userinput> ---- -- my -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.dirname(<replaceable>path-name</replaceable>)</emphasis></term> - <listitem> - <para> - Given a full path name, remove the final part (the file name). - </para> - <para> - Parameters: (type = string) path name. - </para> - <para> - Returns: directory name, that is, path name except for file name. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.dirname('/path/to/my.lua')</userinput> ---- -- /path/to/ -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.umask(<replaceable>mask-bits</replaceable>)</emphasis></term> - <listitem> - <para> - Set the mask bits used when creating files or directories. For a detailed description type "man 2 umask". - </para> - <para> - Parameters: (type = number) mask bits. - </para> - <para> - Returns: (type = number) previous mask bits. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.umask(tonumber('755', 8)) -- pass 755 octal</userinput> ---- -- 493 -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.lstat or fio.stat(<replaceable>path-name</replaceable>)</emphasis></term> - <listitem> - <para> - Returns information about a file object. - For details type "man 2 lstat" or "man 2 stat". - </para> - <para> - Parameters: (string) path-name of file. - </para> - <para> - Returns: (type = table) fields which describe the file's block size, creation time, size, and other attributes. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.lstat('/etc')</userinput> ---- -- inode: 1048577 - rdev: 0 - size: 12288 - atime: 1421340698 - mode: 16877 - mtime: 1424615337 - nlink: 160 - uid: 0 - blksize: 4096 - gid: 0 - ctime: 1424615337 - dev: 2049 - blocks: 24 -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.mkdir or fio.rmdir(<replaceable>path-name</replaceable>)</emphasis></term> - <listitem> - <para> - Create or delete a directory. For details type "man 2 mkdir" or "man 2 rmdir". - </para> - <para> - Parameters: (type = string) path of directory. - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.mkdir('/etc')</userinput> ---- -- false -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.glob(<replaceable>path-name</replaceable>)</emphasis></term> - <listitem> - <para> - Return a list of files that match an input string. - The list is constructed with a single flag that controls the behavior of the function: GLOB_NOESCAPE. - For details type "man 3 glob". - </para> - <para> - Parameters: (type = string) path-name, which may contain wildcard characters. - </para> - <para> - Returns: (type = table) list of files whose names match the input string, or nil if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.glob('/etc/x*')</userinput> ---- -- - /etc/xdg - - /etc/xml - - /etc/xul-ext -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.tempdir()</emphasis></term> - <listitem> - <para> - Return the name of a directory that can be used to store temporary files. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.tempdir()</userinput> ---- -- /tmp/lG31e7 - ...</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.link or fio.symlink or fio.readlink or fio.unlink(<replaceable>path-name</replaceable> [, <replaceable>path-name</replaceable>])</emphasis></term> - <listitem> - <para> - Functions to create and delete links. - For details type "man readlink", "man 2 link", "man 2 symlink", "man 2 unlink".. - </para> - <para> - Parameters: (type = string) existing file name, (type = string) linked name. - </para> - <para> - Returns: <code>fio.link</code> and <code>fio.symlink</code> and <code>fio.unlink</code> return true if success, false if failure. <code>fio.readlink</code> returns the link value if success, nil if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.link('/home/username/tmp.txt', '/home/username/tmp.txt2')</userinput> ---- -- true -... -<prompt>tarantool></prompt> <userinput>fio.unlink('/home/pgulutzan/tmp.txt2')</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.rename(<replaceable>path-name</replaceable>, <replaceable>new-path-name</replaceable>)</emphasis></term> - <listitem> - <para> - Rename a file or directory. - For details type "man 2 rename". - </para> - <para> - Parameters: (type = string) original name, (type = string) new name. - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.rename('/home/username/tmp.txt', '/home/username/tmp.txt2')</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.chown or fio.chmod(<replaceable>path-name</replaceable>,<replaceable>new rights or new owner</replaceable>)</emphasis></term> - <listitem> - <para> - Manage the rights to file objects, or ownership of file objects. For details type "man 2 chown" or "man 2 chmod". - </para> - <para> - Parameters: (for chown) number (uid, gid) and group group name or user name. - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.chmod('/home/username/tmp.txt', tonumber('0755', 8))</userinput> ---- -- true -... - <userinput>fio.chown('/home/username/tmp.txt', 'username', 'username')</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.truncate(<replaceable>path-name</replaceable>,<replaceable>new-size</replaceable>)</emphasis></term> - <listitem> - <para> - Reduce file size to a specified value. For details type "man 2 truncate". - </para> - <para> - Parameters: (type = string) path-name, (type = number) new-size. - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.truncate('/home/username/tmp.txt', 99999)</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.sync()</emphasis></term> - <listitem> - <para> - Ensure that changes are written to disk. For details type "man 2 sync". - </para> - <para> - Parameters: none - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fio.sync()</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">fio.open(<replaceable>path-name</replaceable>[, <replaceable>flags</replaceable>])</emphasis></term> - <listitem> - <para> - Open a file in preparation for reading or writing or seeking. - </para> - <para> - Parameters: (string) path-name, (number) flags. Flags can be passed as a number or as string constants, for example 'O_RDONLY', 'O_WRONLY', 'O_RDWR'. - Flags can be combined by enclosing them in braces. - </para> - <para> - Returns: (type = table) if success = a file handle (referred to in later examples as "fh"), if failure = nil. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh = fio.open('/home/username/tmp.txt', {'O_RDWR', 'O_APPEND'})</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>fh -- display file handle returned by fio.open</userinput> ---- -- fh: 11 -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>file-handle</replaceable>:close()</emphasis></term> - <listitem> - <para> - Close a file that was opened with fio.open. For details type "man 2 close". - </para> - <para> - Parameters: (type = table) file handle as returned by <code>fio.open()</code>. - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh:close() -- where fh = file-handle</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>file-handle</replaceable>:pread or <replaceable>file-handle</replaceable>:pwrite(<replaceable>count or new string</replaceable>, <replaceable>offset</replaceable>)</emphasis></term> - <listitem> - <para> - Perform read/write random-access operation on a file, without affecting the current seek position of the file. - For details type "man 2 pread" or "man 2 pwrite". - </para> - <para> - Parameters: (type = table) file-handle as returned by <code>fio.open</code>, - (type = string) value to write or (type = number) number of bytes to read, - (type = number) offset within file where reading or writing begins. - </para> - <para> - Returns: <code>pwrite</code> returns true if success, false if failure. <code>pread</code> returns the data that was read, or nil if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh:read(25, 25)</userinput> ---- -- |- - elete from t8// - insert in -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>file-handle</replaceable>:read or <replaceable>file-handle</replaceable>:write(<replaceable>count or new string</replaceable>)</emphasis></term> - <listitem> - <para> - Perform non-random-access read or write on a file. For details type "man 2 read" or "man 2 write". - Important: <code>read</code> and <code>write</code> affect the seek position within the file, - and this must be taken into account when working on the same file from multiple fibers. - It is possible to limit or prevent or prevent file access from other fibers with <code>fiber.ipc</code>. - </para> - <para> - Parameters: (type = table) file-handle as returned by <code>fio.open</code>, (type = string) value to write or (type = number) number of bytes to read. - </para> - <para> - Returns: <code>write</code> returns true if success, false if failure. <code>read</code> returns the data that was read, or nil if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh:write('new data')</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>file-handle</replaceable>:truncate(<replaceable>new-size</replaceable>)</emphasis></term> - <listitem> - <para> - Change the size of an open file. - Differs from <code>fio.truncate</code>, which changes the size of a closed file. - </para> - <para> - Parameters: (type = table) file-handle as returned by <code>fio.open</code>, (type = number) new file size. - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <para> - Possible errors: - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh:truncate(0)</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>file-handle</replaceable>:seek(<replaceable>position</replaceable> [, <replaceable>offset-from</replaceable>)</emphasis></term> - <listitem> - <para> - Shift position in the file to the specified position. - For details type "man 2 seek". - </para> - <para> - Parameters: (type = table) file handle as returned by <code>fio.open</code>, - (type = number) position to seek to, (type = constant string) 'SEEK_END' = end of file, - 'SEEK_CUR' = current position, 'SEEK_SET' = start of file. - </para> - <para> - Returns: (type = number) the new position if success, nil if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh:seek(20, 'SEEK_SET')</userinput> ---- -- 20 -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>file-handle</replaceable>:stat()</emphasis></term> - <listitem> - <para> - Return statistics about an open file. - This differs from <code>fio.stat</code> which return statistics about a closed file. - For details type "man 2 stat". - </para> - <para> - Parameters: (type = table) file handle as returned by <code>fio.open()</code>. - </para> - <para> - Returns: (type = table) details about the file. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh:stat()</userinput> ---- -- inode: 729866 - rdev: 0 - size: 100 - atime: 1409429855 - mode: 33261 - mtime: 1409430660 - nlink: 1 - uid: 1000 - blksize: 4096 - gid: 1000 - ctime: 1409430660 - dev: 2049 - blocks: 8 -... -</programlisting> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>file-handle</replaceable>:fsync or <replaceable>file-handle</replaceable>:fdatasync ()</emphasis></term> - <listitem> - <para> - Ensure that file changes are written to disk, for an open file. - Compare <code>fio.sync</code>, which is for all files. - For details type "man 2 fsync" or "man 2 fdatasync". - </para> - <para> - Parameters: (type = table) file-handle, as returned by <code>fio.open()</code>. - </para> - <para> - Returns: (type = boolean) true if success, false if failure. - </para> - <bridgehead renderas="sect4">Example</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>fh:fsync()</userinput> ---- -- true -... -</programlisting> - </listitem> - </varlistentry> - - </variablelist> -</section> - - -<section xml:id="sp-console"> - <title>package <code>console</code></title> - - <para> - The console package allows one Tarantool server - to access another Tarantool server, and allows - one Tarantool server to start listening on an - administrative host/port. - </para> - - -<variablelist> - - <varlistentry> - <term xml:id="console-connect" xreflabel="console-connect"><emphasis role="lua">console.connect(<replaceable>URI</replaceable>[, <replaceable>options</replaceable>])</emphasis></term> - <listitem> - <para> - Connect to the server at <link linkend="URI">URI</link>, change the prompt from - 'tarantool' to 'host:port', and act henceforth as a client - until the user ends the session or types control-D. - </para> - <para> - The console.connect function allows one Tarantool server, - in interactive mode, to access another Tarantool - server over a TCP connection. Subsequent requests - will appear to be handled locally, but in reality - the requests are being sent to the remote server - and the local server is acting as a client. - Once connection is successful, the prompt - will change and subsequent requests are sent - to, and executed on, the remote server. - Results are displayed on the local server. - To return to local mode, enter control-D. - </para> - <para> - There are no restrictions on the types of requests - that can be entered, except those which are due to - privilege restrictions -- by default the login to the remote - server is done with user name = 'guest'. The remote - server could allow for this by granting at least - one privilege: - <code>box.schema.user.grant('guest','execute','universe')</code>. - </para> - <para> - Parameters: <code>URI</code>, <code>options</code>. - The options may be necessary if the Tarantool server at host:port requires - authentication. In such a case the connection might look something like: - <code>console.connect('netbox:123@127.0.0.1'})</code>. - </para> - <para> - Returns: nothing. - </para> - <para> - Possible errors: the connection will fail if the target Tarantool server - was not initiated with <code>box.cfg{listen=...}</code>. - </para> - <para> - <bridgehead renderas="sect4">Example showing use of console</bridgehead><programlisting> -<prompt>tarantool></prompt> <userinput>console = require('console')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>console.connect('198.18.44.44:3301')</userinput> ---- -... -<prompt>198.18.44.44:3301></prompt> <userinput>-- prompt is telling us that server is remote</userinput></programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">console.listen(<replaceable>host</replaceable>,<replaceable>port</replaceable>)</emphasis></term> - <listitem> - <para> - Listen on host:port. The primary way of listening for incoming - requests is via the host and port, or <link linkend="URI">URI</link>, specified in - <code>box.cfg{listen=...}</code>. The alternative way of - listening is via the host and port, or URI, specified in - <code>console.listen(...)</code>. This alternative way is - called "administrative" or simply "admin port". - </para> - <para> - Parameters: <code>host</code>, <code>port</code>. - The listening is usually over a local host with a Unix socket, - specified as host = 'unix/', port = 'path/to/something.sock'. - </para> - <para xml:id="admin_port" xreflabel="admin_port"> - The "admin" address is the port or <link linkend="URI">URI</link> to listen on for administrative - connections. It has no default value, so it must be specified - if connections will occur via telnet. It is not used unless - assigned a value. The parameters may be expressed with URI = Universal - Resource Identifier format, for example "unix://unix_domain_socket", - or as a numeric TCP port. Connections are often made with telnet. - A typical port value is 3313. - </para> - </listitem> - </varlistentry> - - - - </variablelist> - - - - - - -</section> - - -<section xml:id="sp-log"> - <title>package <code>log</code></title> - <para> - The Tarantool server puts all diagnostic messages in a log file - specified by the <link linkend="logger">logger</link> - configuration parameter. Diagnostic messages may be either - system-generated by the server's internal code, or user-generated - with the <code>log.<replaceable>log_level_function_name</replaceable></code> function. - </para> -<variablelist> - <varlistentry> - <term><emphasis role="lua">log.<replaceable>log_level_function_name</replaceable>(<replaceable>log_message</replaceable>)</emphasis></term> - <listitem> - <para> - Output a user-generated message to the <link linkend="logger">log file</link>, given - log_level_function_name = <code>error</code> or <code>warn</code> or <code>info</code> - or <code>debug</code> or <code>rotate</code>. - </para> - <para> - Returns: nothing. - </para> - <para> - Parameters: (type = string) log_message. The actual output will be a - line containing the current timestamp, a module name, 'E' or 'W' or 'I' or 'D' or 'R' depending on - log_level_function_name, and log_message. Output will not occur if log_level_function_name is for a type greater than - <link linkend="log_level">log_level</link>. - </para> - <para> - <bridgehead renderas="sect4">Example showing use of log</bridgehead><programlisting> -#From the shell: -#Start the server, do some requests, exit, and display the log, thus: -~/tarantool/src/tarantool -box.cfg{log_level=3, logger='tarantool.txt'} -log = require('log') -log.error('Error') -log.info('Info') -os.exit() -less tarantool.txt -</programlisting> - The output from the <code>less</code> command will look approximately like this: -<programlisting> -2014-09-21 17:58:40.820 [5257] main/101/interactive C> version 1.6.3-355-ga4f762d -2014-09-21 17:58:40.821 [5257] main/101/interactive C> log level 3 -2014-09-21 17:58:40.821 [5261] main/101/spawner C> initialized -2014-09-21 17:58:40.830 [5257] main/101/interactive [C]:-1 E> Error -</programlisting> - The 'Error' line is visible in tarantool.txt preceded by the letter E. - The 'Info' line is not present because the log_level is 3. - </para> - </listitem> - </varlistentry> - </variablelist> -</section> - -<section xml:id="sp-tap"> - <title>package <code>tap</code></title> - <para> - The tap package streamlines the testing of other packages. - It allows writing of tests in the <link xlink:href="https://en.wikipedia.org/wiki/Test_Anything_Protocol">TAP protocol</link>. - The results from the tests can be parsed by standard TAP-analyzers - so they can be passed to utilities such as <link xlink:href="https://metacpan.org/pod/distribution/Test-Harness/bin/prove">prove</link>. - Thus one can run tests and then use the results for statistics, decision-making, and so on. - </para> -<variablelist> - - <varlistentry> - <term><emphasis role="lua">tap.test(<replaceable>test-name</replaceable>)</emphasis></term> - <listitem> - <para> - Initialize -- the result of <code>tap.test</code> is an object, - which will be called <code>taptest</code> in the rest of this discussion, - which is necessary for <code>taptest:plan()</code> and all the other methods. - </para> - <para> - Returns: (table) taptest. - </para> - <para> - Parameters: (type = string) test-name = an arbitrary name to give for the test outputs. - </para> - <para> - Example: <code><userinput>tap = require('tap') taptest = tap.test('test-name')</userinput></code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:plan(<replaceable>count</replaceable>)</emphasis></term> - <listitem> - <para> - Indicate how many tests will be performed. - </para> - <para> - Returns: nothing. - </para> - <para> - Parameters: (type = number) count. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:check()</emphasis></term> - <listitem> - <para> - Checks the number of tests performed. - This check should only be done after all planned tests are complete, - so ordinarily <code>taptest:check()</code> will only appear at the end of a script. - </para> - <para> - Returns: nothing. Will display '# bad plan: ...' if the number of completed - tests is not equal to the number of tests specified by <code>taptest:plan(...)</code>. - </para> - <para> - Parameters: none. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:diag(<replaceable>message</replaceable>)</emphasis></term> - <listitem> - <para> - Display a diagnostic message. - </para> - <para> - Returns: nothing. The message will be displayed. - </para> - <para> - Parameters: the message to be displayed. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:ok(<replaceable>condition</replaceable>, <replaceable>test-name</replaceable>)</emphasis></term> - <listitem> - <para> - This is a basic function which is used by other functions. - Depending on the value of <code>condition</code>, print 'ok' or 'not ok' along with debugging information. - </para> - <para> - Returns: true or false. Also displays 'true' or 'false'. - </para> - <para> - Parameters: (boolean expression) <code>condition</code> == an expression which is true or false, (string) test-name. - </para> - <para> - Example:<programlisting>tarantool> <userinput>taptest:ok(true,'x')</userinput> -ok - x ---- -- true -... -tarantool> <userinput>tap = require('tap')</userinput> ---- -... -tarantool> <userinput>taptest = tap.test('test-name')</userinput> -TAP version 13 ---- -... -tarantool> <userinput>taptest:ok(1 + 1 == 2, 'X')</userinput> -ok - X ---- -- true - ...</programlisting></para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:fail(<replaceable>test-name</replaceable>)</emphasis></term> - <listitem> - <para> - <code>taptest:fail('x')</code> is equivalent to <code>taptest:ok(false, 'x')</code>. - </para> - <para> - Returns: true or false. - </para> - <para> - Parameters: (string) test-name. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:skip(<replaceable>message</replaceable>)</emphasis></term> - <listitem> - <para> - <code>taptest:skip('x')</code> is equivalent to <code>taptest:ok(true, 'x' .. '# skip')</code>. - </para> - <para> - Returns: nothing. Displays the message - </para> - <para> - Parameters: (string) message. - </para> - <para> - Example: <code>taptest:skip('message')</code> will return <code>ok - message # skip</code>. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:is(<replaceable>got</replaceable>, <replaceable>expected</replaceable>, <replaceable>test-name</replaceable>)</emphasis></term> - <listitem> - <para> - Check whether the first argument equals the second argument. - </para> - <para> - Returns: true or false. Displays extensive message if the result is false. - </para> - <para> - Parameters: (number) <code>got</code> = actual result, (number) <code>expected</code> = expected result, (string) test-name. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:isnt(<replaceable>got</replaceable>, <replaceable>expected</replaceable>, <replaceable>test-name</replaceable>)</emphasis></term> - <listitem> - <para> - This is the negation of <code>taptest:is(...)</code>. - </para> - <para> - Returns: true or false. - </para> - <para> - Parameters: (number) <code>got</code> = actual result, (number) <code>expected</code> = expected result, (string) test-name. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:is<replaceable>type-name</replaceable>(<replaceable>value</replaceable>, <replaceable>test-name</replaceable>)</emphasis></term> - <listitem> - <para> - Test whether a value has a particular type. The possible functions in this group are: - <code>isnil</code>, <code>isstring</code>, <code>isnumber</code>, <code>istable</code>, <code>isboolean</code>, <code>isudata</code>, <code>iscdata</code>. - </para> - <para> - Returns: true or false. Displays a long message if the value is not of the specified type. - </para> - <para> - Parameters: (nil or string or number or table or boolean or udata or cdata) value, (string) test-name. - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua"><replaceable>taptest</replaceable>:is_deeply(<replaceable>got</replaceable>,<replaceable>expected</replaceable>, <replaceable>test-name</replaceable>)</emphasis></term> - <listitem> - <para> - Recursive version of <code>taptestis(...)</code>, which can be - be used to compare tables as well as scalar values. - </para> - <para> - Returns: true or false. - </para> - <para> - Parameters: (number or table) <code>got</code> = actual result, (number or table) <code>expected</code> = expected result, (string) test-name. - </para> - - <para> - <bridgehead renderas="sect4">Example Lua script showing use of tap</bridgehead> - To run this example: put the script in a file named ./tap.lua, then make tap.lua - executable by saying <code>chmod a+x ./tap.lua</code>, then execute using Tarantool - as a script processor by saying <code>./tap.lua</code>. - <programlisting> -#!/usr/bin/tarantool -local tap = require('tap') -test = tap.test("my test name") -test:plan(2) -test:ok(2 * 2 == 4, "2 * 2 is 4") -test:test("some subtests for test2", function(test) - test:plan(2) - test:is(2 + 2, 4, "2 + 2 is 4") - test:isnt(2 + 3, 4, "2 + 3 is not 4") -end) -test:check() -</programlisting> - The output from the above script will look approximately like this: -<programlisting> -TAP version 13 -1..2 -ok - 2 * 2 is 4 - # Some subtests for test2 - 1..2 - ok - 2 + 2 is 4, - ok - 2 + 3 is not 4 - # Some subtests for test2: end -ok - some subtests for test2 -</programlisting> - </para> - </listitem> - </varlistentry> - </variablelist> -</section> - -<section xml:id="sp-tonumber64"> - <title>Lua functions <code>tonumber64</code> and <code>dostring</code></title> - -<variablelist> - - <varlistentry> - <term xml:id="tonumber64" xreflabel="tonumber64"> <emphasis role="lua">tonumber64(<replaceable>value</replaceable>)</emphasis></term> - <listitem> - <para> - Convert a string or a Lua number to a - 64-bit integer. The result can be used in arithmetic, - and the arithmetic will be 64-bit integer arithmetic - rather than floating-point arithmetic. (Operations on - an unconverted Lua number use floating-point arithmetic.) - The tonumber64() function is added by Tarantool; the name is global. - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>type(123456789012345), type(tonumber64(123456789012345))</userinput> ---- -- number -- number -... -tarantool> <userinput>i = tonumber64('1000000000')</userinput> ---- -... -tarantool> <userinput>type(i), i / 2, i - 2, i * 2, i + 2, i % 2, i ^ 2</userinput> ---- - - number - - 500000000 - - 999999998 - - 2000000000 - - 1000000002 - - 0 - - 1000000000000000000 -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term> - <emphasis role="lua">dostring(<replaceable>lua-chunk-string [, lua-chunk-string-argument ...]</replaceable>)</emphasis> - </term> - <listitem> - <para> - Parse and execute an arbitrary chunk of Lua code. - This function is mainly useful to define and run - Lua code without having to - introduce changes to the global Lua environment. - </para> - <para> - Parameters: <code>lua-chunk-string</code> = string containing Lua code, - <code>lua-chunk-string-argument(s)</code> = zero or more scalar values - which will be appended to, or substitute for, items in the Lua chunk. - </para> - <para> - Returns: whatever is returned by the Lua code chunk. - </para> - <para> - Possible errors: If there is a compilation error, - it is raised as a Lua error. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>dostring('abc')</userinput> ---- -error: '[string "abc"]:1: ''='' expected near ''<eof>''' -... -tarantool> <userinput>dostring('return 1')</userinput> ---- -- 1 -... -tarantool> <userinput>dostring('return ...', 'hello', 'world')</userinput> ---- -- hello -- world -... -tarantool> <userinput>console = require('console'); console.delimiter('!') --<link linkend="utility-tarantool-delim">this</link> means ignore line feeds until next '!'</userinput> -tarantool> <userinput>-- Use <link xlink:href="http://www.lua.org/pil/2.4.html">double square brackets</link> to enclose multi-line literal here!</userinput> -tarantool> <userinput>dostring([[local f = function(key)</userinput> - -> <userinput> t = box.space.tester:select{key};</userinput> - -> <userinput> if t ~= nil then return t[1] else return nil end</userinput> - -> <userinput> end</userinput> - -> <userinput> return f(...)]], 1)!</userinput> ---- -- null -... -tarantool> <userinput>console.delimiter('')!</userinput> -</programlisting> - </para> - </listitem> - </varlistentry> - -</variablelist> - -</section> - - -<section xml:id="sp-pickle"> - <title>Package <code>pickle</code></title> -<variablelist xml:id="x-pickle" xreflabel="x-pickle"> - <varlistentry> - <term><emphasis role="lua">pickle.pack(<replaceable>format, argument [, argument ...]</replaceable>)</emphasis></term> - <listitem><para> - To use Tarantool binary protocol primitives from Lua, - it's necessary to convert Lua variables to binary - format. The pickle.pack() helper function is prototyped after Perl - <link xlink:href="http://perldoc.perl.org/functions/pack.html"> - 'pack'</link>. - </para> - <para> - Parameters: <code>format</code> = string containing format specifiers, <code>argument(s)</code> = scalar values to be formatted. - </para> - <para> - <bridgehead renderas="sect4">Format specifiers</bridgehead> - <simplelist> - <member><code>b</code> or <code>B</code> — converts Lua - variable to a 1-byte - integer, and stores the integer in the resulting - string, - </member> - <member><code>s</code> or <code>S</code> — converts Lua - variable to a 2-byte - integer, and stores the integer in the resulting - string, low byte first, - </member> - <member><code>i</code> or <code>I</code> — converts Lua - variable to a 4-byte - integer, and stores the integer in the resulting - string, low byte first, - </member> - <member><code>l</code> or <code>L</code> — converts Lua - variable to an 8-byte - integer, and stores the integer in the resulting - string, low byte first, - </member> - <member><code>n</code> or <code>N</code> — converts Lua - variable to a 4-byte - integer, and stores the integer in the resulting - string, big endian, - </member> - <member><code>q</code> or <code>Q</code> — converts Lua - variable to an 8-byte - integer, and stores the integer in the resulting - string, big endian, - </member> - <member><code>f</code> — converts Lua - variable to a 4-byte - float, and stores the float in the resulting - string, - </member> - <member><code>d</code> — converts Lua - variable to a 8-byte - double, and stores the double in the resulting - string, - </member> - <member><code>d</code> — converts Lua - variable to a sequence of bytes, - and stores the sequence in the resulting - string, - </member> - </simplelist> - </para> - <para> - Returns: a binary string containing all arguments, packed - according to the format specifiers. - </para> - <para> - Possible Errors: Unknown format specifier. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -tarantool> <userinput>pickle = require('pickle')</userinput> ---- -... -tarantool> <userinput>box.space.tester:insert{0, 'hello world'}</userinput> ---- -- [0, 'hello world'] -... -tarantool> <userinput>box.space.tester:update({0}, {{'=', 2, 'bye world'}})</userinput> ---- -- [0, 'bye world'] -... -tarantool> <userinput>box.space.tester:update({0}, {{'=', 2, pickle.pack('iiA', 0, 3, 'hello')}})</userinput> ---- -- [0, "\0\0\0\0\x03\0\0\0hello"] -... -tarantool> <userinput>box.space.tester:update({0}, {{'=', 2, 4}})</userinput> ---- -- [0, 4] -... -tarantool> <userinput>box.space.tester:update({0}, {{'+', 2, 4}})</userinput> ---- -- [0, 8] -... -tarantool> <userinput>box.space.tester:update({0}, {{'^', 2, 4}})</userinput> ---- -- [0, 12] -... -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><emphasis role="lua">pickle.unpack(<replaceable>format, binary-string</replaceable>)</emphasis></term> - <listitem> - <para> - Counterpart to <code>pickle.pack()</code>. - </para> - <para> - Parameters: <code>format</code>, <code>binary-string</code>. - </para> - <para> - Returns: (type = scalar) A list of strings or numbers. - </para> - <para> - <bridgehead renderas="sect4">Example</bridgehead> -<programlisting> -<prompt>tarantool</prompt> <userinput>pickle = require('pickle')</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>console = require('console'); console.delimiter('!') -- this means following commands must end with '!'</userinput> -<prompt>tarantool></prompt> <userinput>tuple = box.space.tester:replace{0}!</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>string.len(tuple[1])!</userinput> ---- -- 1 -... -<prompt>tarantool></prompt> <userinput>pickle.unpack('b', tuple[1])!</userinput> ---- -- 48 -... -<prompt>tarantool></prompt> <userinput>pickle.unpack('bsi', pickle.pack('bsi', 255, 65535, 4294967295))!</userinput> ---- -- 255 -- 65535 -- 4294967295 -... -<prompt>tarantool></prompt> <userinput>pickle.unpack('ls', pickle.pack('ls', tonumber64('18446744073709551615'), 65535))!</userinput> ---- -- 18446744073709551615 -- 65535 -... -<prompt>tarantool></prompt> <userinput>num, str, num64 = pickle.unpack('sAl', pickle.pack('sAl', 666, 'string',</userinput> -<prompt> -></prompt> <userinput> tonumber64('666666666666666')))!</userinput> ---- -... -<prompt>tarantool></prompt> <userinput>console.delimiter('') -- back to normal: commands end with line feed!</userinput> -</programlisting> - </para> - </listitem> - </varlistentry> -</variablelist> -</section> - - -<section xml:id="sp-expirationd"> - <title>expirationd -- the daemon that shifts expired tuples to a long-term archive</title> - -<para> -For a commercial-grade example of a Lua rock that works with Tarantool, -let us look at expirationd, which Tarantool supplies on -<link xlink:href="https://github.com/tarantool/expirationd/blob/master/expirationd.lua">GitHub</link> -with an Artistic license. The expirationd.lua program is -lengthy (about 500 lines), so here we will only highlight -the matters that will be enhanced by studying the full source later. -<programlisting> - task.worker_fiber = fiber.create(worker_loop, task) - log.info("expiration: task %q restarted", task.name) - ... - fiber.sleep(expirationd.constants.check_interval) - ... -</programlisting> -Whenever one hears "daemon" in Tarantool, one should suspect it's -being done with <olink targetptr="sp-box-fiber">fibers</olink>. The program is making a fiber -and turning control over to it so it runs occasionally, goes to -sleep, then comes back for more. -<programlisting> - for _, tuple in scan_space.index[0]:pairs(nil, {iterator = box.index.ALL}) do - ... - if task.is_tuple_expired(task.args, tuple) then - task.expired_tuples_count = task.expired_tuples_count + 1 - task.process_expired_tuple(task.space_id, task.args, tuple) - ... -</programlisting> -The "for" instruction can be translated as "iterate through the index of -the space that is being scanned", and within it, if the tuple is "expired" -(that is, if the tuple has a timestamp field which is less than the current -time), process the tuple as an expired tuple. -<programlisting> --- put expired tuple in archive -local function put_tuple_to_archive(space_id, args, tuple) - -- delete expired tuple - box.space[space_id]:delete{tuple[1]} - local email = get_field(tuple, 2) - if args.archive_space_id ~= nil and email ~= nil then - box.space[args.archive_space_id]:replace{email, os.time()} - end -end -</programlisting> -Ultimately the tuple-expiry process leads to put_tuple_to_archive() -which does a "delete" of a tuple from its original space, and an -"insert" of the same tuple into another space. Tarantool's "replace" -function is the same as an "insert" function without an error message -if a tuple with the same content already exists in the target space. -<programlisting> -function expirationd.do_test(space_id, archive_space_id) -... -</programlisting> -At this point, if the above explanation is worthwhile, it's clear that -expirationd.lua starts a background routine (fiber) which iterates -through all the tuples in a space, sleeps cooperatively so that other -fibers can operate at the same time, and -- whenever it finds a tuple -that has expired -- deletes it from this space and puts it in another -space. Now the "do_test()" function can be used to create some sample -spaces, let the daemon run for a while, and print results. -</para> -<para> -For those who like to see things run, here are the exact steps to -get expirationd through the test. -</para> -<para> -1. Get expirationd.lua. - There are standard ways -- it is after all part of <link linkend="rocks">a standard rock</link> -- - but for this purpose just copy the contents of - <link xlink:href="https://github.com/tarantool/expirationd/blob/master/expirationd.lua">https://github.com/tarantool/expirationd/blob/master/expirationd.lua</link> - to a default directory. -</para> -<para> -2. Start the Tarantool server as described <olink targetptr="getting-started-start-stop">before</olink>. -</para> -<para> -3. Execute these requests: -<programlisting><userinput> - box.cfg{} - a = box.schema.space.create('origin') - a:create_index('first', {type = 'tree', parts = {1, 'NUM'}}) - b = box.schema.space.create('archive') - b:create_index('first', {type = 'tree', parts = {1, 'STR'}}) - expd = require('expirationd') - expd._debug = true - expd.do_test('origin', 'archive') - os.exit() -</userinput></programlisting> -The database-specific requests (cfg, space.create, create_index) -should already be familiar. The key for getting the rock rolling is -<code>expd = require('expirationd')</code>. -The "require" function is what reads in the program; it will appear -in many later examples in this manual, when it's necessary to get a -package that's not part of the Tarantool kernel. After the Lua -variable expd has been assigned the value of the expirationd package, -it's possible to invoke the package's <code>do_test()</code> function. -</para> -<para> -After a while, when the task has had time to do its iterations through -the spaces, do_test() will print out a report showing the tuples that -were originally in the original space, the tuples that have now been -moved to the archive space, and some statistics. Of course, expirationd -can be customized to do different things by passing different parameters, -which will be evident after looking in more detail at the source code. -</para> - -</section> - -</section> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/triggers.xml b/doc/user/triggers.xml index 64a3c0867a57bb2d60abf6381e58d2abb1c4a70e..3bdfe3a1fce232351874f55398ab379b84a1851e 100644 --- a/doc/user/triggers.xml +++ b/doc/user/triggers.xml @@ -106,7 +106,7 @@ </term> <listitem><para> Define a trigger for execution when a new session is created due to - an event such as <link linkend="console-connect"><code>console.connect()</code></link>. + 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 @@ -164,7 +164,7 @@ <para> <bridgehead renderas="sect4">Example</bridgehead> After the following series of requests, the server - will write a message using the <link linkend="sp-log">log package</link> + 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 '!' diff --git a/doc/user/tutorial.xml b/doc/user/tutorial.xml index 4a286386beb0cff6e4930203515d9911a3a2b802..a4bc5e15ca797eecbffe043b677dcc7592e98084 100644 --- a/doc/user/tutorial.xml +++ b/doc/user/tutorial.xml @@ -383,7 +383,7 @@ console.connect('localhost:3301') box.space.tester:select{2}</userinput></programlisting> </para> <para> -The requests are saying "use the <link linkend="sp-console">console package</link> to connect to the +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. diff --git a/doc/user/user.xml b/doc/user/user.xml index 1b8d148ae9bba99c3bcf7dbd2ddee036ae8b7b84..fcc312910291cd1d517479676d47ff7253f1ef0f 100644 --- a/doc/user/user.xml +++ b/doc/user/user.xml @@ -10,7 +10,6 @@ <title>Tarantool User Guide, version &tnt_version;</title> <xi:include href="preface.xml"/> <xi:include href="tutorial.xml"/> -<xi:include href="lua-and-packages.xml"/> <xi:include href="databases.xml"/> <xi:include href="triggers.xml"/> <xi:include href="replication.xml"/> diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index d9a622e7b3634347eb49fd53e779b25abed59abe..be134f513847b37597850c49776af67349e09f96 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -151,13 +151,13 @@ local function prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg, prefix) if cfg.dont_check then return end - readable_prefix = '' + local readable_prefix = '' if prefix ~= nil and prefix ~= '' then readable_prefix = prefix .. '.' end local new_cfg = {} for k,v in pairs(cfg) do - readable_name = readable_prefix .. k; + local readable_name = readable_prefix .. k; if template_cfg[k] == nil then error("Error: cfg parameter '" .. readable_name .. "' is unexpected") elseif v == "" or v == nil then diff --git a/src/lib/bit/int96.h b/src/lib/bit/int96.h index 8434d29c28d26fcdbaea4aa87041aa9b0e423a86..39b754ae79f168bc78a7b4add123814a362afe0a 100644 --- a/src/lib/bit/int96.h +++ b/src/lib/bit/int96.h @@ -32,9 +32,6 @@ #include <inttypes.h> #include <assert.h> -#ifdef __cplusplus -extern "C" { -#endif /** * 96-bit signed integer. * 1)Negative integer is stored as 96-bit two's complement @@ -42,13 +39,13 @@ extern "C" { * Actually (1) == (2), as the wave-particle duality. * Designed for storing integers in range [INT64_MIN, UINT64_MAX], * and detecting overflow (out of range [INT64_MIN, UINT64_MAX]) - * after operations (addition, substruction) on them. + * after operations (addition, subtraction) on them. * The base fact is when two uint64_t or int64_t values - * are converted to int96, and then added or substructed, the + * are converted to int96, and then added or subtracted, the * int96 arithmetics cannot overflow. Actually you need at least * billions of adding UINT64_MAX or INT64_MIN to make it overflow. * Addition is implemented directly; - * For substraction use addition of inverted number. + * For subtraction use addition of inverted number. */ /** @@ -154,7 +151,7 @@ int96_is_neg_int64(const struct int96_num *num) /** * Get number as negative int64_t, - * the nymber is expected to be valid range (assert) + * the number is expected to be valid range (assert) */ static inline int64_t int96_extract_neg_int64(const struct int96_num *num) @@ -163,8 +160,4 @@ int96_extract_neg_int64(const struct int96_num *num) return (int64_t)int96_get_low64bit(num); } -#ifdef __cplusplus -} /* extern "C" { */ -#endif - #endif /* #ifndef TARANTOOL_LIB_BIT_INT96_H_INCLUDED */ diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua index 157861935ae741c2fd068ebde4934dd6ea4aa84d..7dbc4a65f783aa07231c925672cee5e2a02bc41d 100644 --- a/src/lua/bsdsocket.lua +++ b/src/lua/bsdsocket.lua @@ -1001,6 +1001,7 @@ end local function tcp_server_handler(server, sc, from) fiber.name(sprintf("%s/%s:%s", server.name, from.host, from.port)) server.handler(sc, from) + sc:shutdown() sc:close() end diff --git a/src/lua/console.lua b/src/lua/console.lua index 24165563190a7aaeaae7edb0ac0bb5775e5f7d1f..83b981ddbcf000b6bc02b68ae924d59366242388 100644 --- a/src/lua/console.lua +++ b/src/lua/console.lua @@ -163,9 +163,7 @@ local function client_print(self, output) return elseif not output then -- disconnect peer - self.client:shutdown() - self.client:close() - self.client = nil + self.client = nil -- socket will be closed by tcp_server() function self.running = nil return end