Skip to content
Snippets Groups Projects
Commit 9790b40e authored by Konstantin Osipov's avatar Konstantin Osipov
Browse files

Merge branch 'master' of github.com:tarantool/tarantool

parents a5adce7c f2bbe928
No related branches found
No related tags found
No related merge requests found
Showing
with 1675 additions and 22 deletions
!.gitignore !.gitignore
*.pyc
$(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
...@@ -250,10 +250,71 @@ tr.field td p { ...@@ -250,10 +250,71 @@ tr.field td p {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAEAAAAAARAQMAAABnOfukAAAABlBMVEUAAAD19fWydBufAAAAAXRSTlMAQObYZgAAADZJREFUaN7t0gEBAAAIAiD/n7YBTRA2kO4InwDruiMIgAAIgAAIgAAIsK47ggAIgAAIgAAIwAHksoxHlAvP9AAAAABJRU5ErkJggg==') 50% -0px repeat-y; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAEAAAAAARAQMAAABnOfukAAAABlBMVEUAAAD19fWydBufAAAAAXRSTlMAQObYZgAAADZJREFUaN7t0gEBAAAIAiD/n7YBTRA2kO4InwDruiMIgAAIgAAIgAAIsK47ggAIgAAIgAAIwAHksoxHlAvP9AAAAABJRU5ErkJggg==') 50% -0px repeat-y;
} }
div.toctree-wrapper.compound {
padding: 20px 0px 0px 0px;
}
div.highlight { 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 { div.admonition {
padding: 20px 0px 0px 0px; -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;
} }
{% import "menu" as menu %} {% import "menu" as menu %}
{% include "custom_sphinx" with context %} {% include "custom_sphinx" with context %}
...@@ -7,7 +8,7 @@ ...@@ -7,7 +8,7 @@
<head> <head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> <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="shortcut icon" href="/theme/favicon.ico" />
<link rel="stylesheet" href="/theme/design.css" /> <link rel="stylesheet" href="/theme/design.css" />
<link rel="stylesheet" href="/theme/pygmentize.css" /> <link rel="stylesheet" href="/theme/pygmentize.css" />
......
...@@ -5,22 +5,7 @@ ...@@ -5,22 +5,7 @@
{% block header_scripts %} {% block header_scripts %}
<link rel="stylesheet" href="/doc/_static/sphinx_design.css" /> <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"> <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<script> <script type="text/javascript" src="../_static/headers.js"></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>
{{ super() }} {{ super() }}
{% endblock header_scripts %} {% endblock header_scripts %}
......
...@@ -18,7 +18,7 @@ import os ...@@ -18,7 +18,7 @@ import os
# If extensions (or modules to document with autodoc) are in another directory, # 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 # 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. # 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 ------------------------------------------------ # -- General configuration ------------------------------------------------
...@@ -28,10 +28,12 @@ import os ...@@ -28,10 +28,12 @@ import os
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [ extensions = [
'sphinx.ext.todo', 'sphinx.ext.todo',
'sphinx.ext.mathjax', 'sphinx.ext.mathjax',
'sphinx.ext.ifconfig', 'sphinx.ext.ifconfig',
'ext.filters'
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
......
# -*- 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}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
:maxdepth: 1 :maxdepth: 1
intro.rst intro.rst
faq.rst
.. raw:: html .. raw:: html
...@@ -19,5 +20,5 @@ ...@@ -19,5 +20,5 @@
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
faq.rst reference/index.rst
dev_guide/index.rst dev_guide/index.rst
.. 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
.. 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
.. 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
.. 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
.. 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
.. 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
---
...
.. 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
...
-------------------------------------------------------------------------------
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
.. 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
.. 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
.. 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/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment