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

Merge branch 'ocelot-master'

parents f4722a61 e92530c1
No related branches found
No related tags found
No related merge requests found
......@@ -70,43 +70,29 @@ is in file <link xlink:href="http://tarantool.org/doc/box-protocol.html" xlink:t
</thead>
<tbody>
<row>
<entry>type</entry>
<entry>13</entry>
<entry>0</entry>
<entry>0</entry>
<entry>0</entry>
</row>
<row>
<entry>body_length</entry>
<entry>17</entry>
<entry>0</entry>
<entry>0</entry>
<entry>0</entry>
</row>
<row>
<entry>request_id</entry>
<entry>1</entry>
<entry>0</entry>
<entry>0</entry>
<entry>0</entry>
</row>
<row>
<entry>flags</entry>
<entry>code for insert</entry>
<entry>2</entry>
<entry>0</entry>
<entry>0</entry>
<entry>0</entry>
</row>
<row>
<entry>map-element count</entry>
<entry>82</entry>
<entry>10</entry>
<entry>rest of header</entry>
<entry>...</entry>
<entry>...</entry>
<entry>...</entry>
<entry>...</entry>
</row>
<row>
<entry>2-digit number: space id</entry>
<entry>cd</entry>
<entry>02</entry>
<entry>03</entry>
<entry>01</entry>
</row>
<row>
<entry>code for tuple</entry>
<entry>21</entry>
</row>
<row>
<entry>1-digit number: field count = 2</entry>
<entry>92</entry>
</row>
<row>
<entry>1-character string: field[1]</entry>
......@@ -129,92 +115,10 @@ of the packet format for responses as well as requests).
But it would be easier, and less error-prone, if one could
invoke a routine that formats the packet according to typed
parameters. Something like <code>response=tarantool_routine("insert",0,"A","B");</code>.
And that is why APIs exist for drivers for C, Perl, Python, PHP, Ruby, and so on.
And that is why APIs exist for drivers for Perl, Python, PHP, and so on.
</para>
</section>
<section xml:id="connector-c">
<title>C</title>
<para>
Here is a complete C program that inserts [99999,'BB'] into space[513] via the C API for the
binary protocol. To compile, paste the code into a file named example.c and say <code>
gcc -o example example.c -I/<replaceable>tarantool-directory</replaceable>/connector/c/include</code>
where tarantool-directory = the directory that contains
the necessary file <filename>tp.h</filename>, and the default library path contains
the directory where Tarantool library files were placed at installation time.
Before trying to run, check that the server
(tarantool) is running on localhost (127.0.0.1) and its listen address is the default
(local host, port 3301) and
space[513]'s primary key type is numeric (space[513].index[0].key_field[1].type = "NUM").
To run, say <code>./example</code>.
The program will open a socket connection with the tarantool server at localhost:3301,
then format a buffer for sending an INSERT request, then send the request, then check if the
server returned an error, then &mdash; if all is well &mdash; print "Insert succeeded". If the
row already exists, the program will print <quote>Duplicate key exists in unique index 0</quote>.
</para>
<programlisting language="cpp">
#include &lt;arpa/inet.h&gt;
#include &lt;stdio.h&gt;
#define MP_SOURCE 1
#include &lt;tp.h&gt; /* the usual Tarantool include */
int main()
{
struct tp request; /* area for sending to server */
struct tpgreeting greet; /* area for the server's greeting */
struct tpresponse response; /* area for translation of reply */
int fd; /* file descriptor for socket */
struct sockaddr_in sock; /* the usual socket address info */
if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) &lt;= 0) /* open the socket. abort if failure */
exit(1);
memset(&amp;sock, 0, sizeof(sock)); /* connect to localhost:3301 */
sock.sin_family = AF_INET;
sock.sin_addr.s_addr = inet_addr("127.0.0.1");
sock.sin_port = htons(3301);
if (connect(fd, (struct sockaddr *)&amp;sock, sizeof(sock)) &lt; 0) /* connect, abort if failure */
exit(1);
const int greeting_buffer_size = 128; /* handle the server's greeting */
char greeting_buffer[greeting_buffer_size];
if (read(fd, greeting_buffer, greeting_buffer_size) != 128) /* greeting must be 128 bytes long */
exit(1);
tp_greeting(&amp;greet, greeting_buffer, 128); /*
char request_buffer[1024]; /* initialize request buffer */
tp_init(&amp;request, request_buffer, 1024, 0, 0);
tp_insert(&amp;request, 513); /* append INSERT header. space_no=513 */
tp_tuple(&amp;request, 2); /* begin appending body, field count = 2 */
tp_encode_uint(&amp;request, 99999); /* append field[1] */
tp_sz(&amp;request, "BB"); /* append field[2] */
int rc = write(fd, tp_buf(&amp;request), tp_used(&amp;request)); /* send the INSERT request */
if (rc != tp_used(&amp;request)) /* abort if send failed */
exit(1);
char reply_buffer[1024];
int rres = read(fd, reply_buffer, 1024); /* get reply */
if (rres &lt;= 0) exit(1);
if (tp_reply(&amp;response, reply_buffer, rres) &lt; 0) exit(1);
if (response.error != 0) { /* display+abort if error e.g. duplicate key */
printf("Error: %*s\n",
(int) (response.error_end-response.error),response.error);
exit(1);
}
close(fd); /* clean up */
printf("Insert succeeded\n"); /* congratulate self */
exit(0);
}
</programlisting>
<para>
The example program only shows one command and does not show all that's necessary for
good practice. For that, please see the <link
xlink:href="https://github.com/tarantool/tarantool-c"><filename>connector/c</filename></link> source tree.
</para>
</section>
<section xml:id="connector-erlang">
<title>Erlang</title>
<para>
Please see <link xlink:href="https://github.com/tarantool/tarantool-erlang"><filename>https://github.com/tarantool/tarantool-erlang</filename></link>.
</para>
</section>
<section xml:id="connector-java">
<title>Java</title>
<para>
......@@ -222,13 +126,6 @@ int main()
</para>
</section>
<section xml:id="connector-node.js">
<title>node.js</title>
<para>
Please see <link xlink:href="https://github.com/devgru/node-tarantool"><filename>http://github.com/devgru/node-tarantool</filename></link>.
</para>
</section>
<section xml:id="connector-perl">
<title>Perl</title>
<para>
......@@ -252,7 +149,7 @@ sudo cpan install DR::Tarantool
Before trying to run, check that the server
(tarantool) is running on localhost (127.0.0.1) and its listen address is the default
(local host, port 3301) and
space[0]'s primary key type is numeric (space[0].index[0].key_field[1].type = "NUM").
space[0]'s primary key type is numeric (box.space[0].index[0].parts[1].type = "NUM").
To run, paste the code into a file named example.pl and say <code>perl example.pl</code>.
The program will connect using an application-specific definition of the space.
The program will open a socket connection
......@@ -309,7 +206,7 @@ cd tarantool-php
phpize
./configure
make
make install
#make install is optional
</programlisting>
</para>
<para>
......@@ -321,15 +218,15 @@ make install
<programlisting>
cd ~
cp ./tarantool-php/modules/tarantool.so .
export PHP_INI_SCAN_DIR=~/tarantool-php/test/share
export PHP_INI_SCAN_DIR=~/tarantool-php/tests/shared
</programlisting>
</para>
<para>
Here is a complete PHP program that inserts [99999,'BB'] into space[0] via the PHP API.
Here is a complete PHP program that inserts [99999,'BB'] into a space named 'tester' via the PHP API.
Before trying to run, check that the server
(tarantool) is running on localhost (127.0.0.1) and its listen address is the default
(local host, port 3301) and
space[0]'s primary key type is numeric (space[0].index[0].key_field[1].type = "NUM").
tester's primary key type is numeric (box.space.tester.index[0].parts[1].type = "NUM").
To run, paste the code into a file named example.php and say <code>php example.php</code>.
The program will open a socket connection
with the tarantool server at localhost:3301, then send an INSERT request,
......@@ -339,9 +236,9 @@ export PHP_INI_SCAN_DIR=~/tarantool-php/test/share
<para>
<programlisting>
&lt;?php
$tarantool = new Tarantool("localhost", 3301, 3313);
$tarantool = new Tarantool("localhost", 3301);
try {
$tarantool-&gt;insert(0, array(99999, "BB"), TARANTOOL_FLAGS_ADD);
$tarantool-&gt;insert("tester", array(99999, "BB"));
print "Insert succeeded\n";
}
catch (Exception $e) {
......@@ -362,12 +259,22 @@ catch (Exception $e) {
<title>Python</title>
<para>
Here is a complete Python program that inserts ['First Tuple','Value','Value'] into space99 via the high-level Python API.
</para>
<programlisting language="python">
#!/usr/bin/python
from tarantool import Connection
c = Connection("127.0.0.1", 3301)
result = c.insert("space99",('First Tuple','Value', 'Value'))
print result
</programlisting>
<para>
To prepare, paste the code into a file named example.py and install tarantool-python with either
<userinput><code>pip install tarantool</code></userinput> to install in <filename>/usr</filename> (requires root privilege)
<userinput><code>pip install tarantool\>0.4</code></userinput> to install in <filename>/usr</filename> (requires root privilege)
or
<userinput><code>pip install tarantool --user</code></userinput> to install in <filename>~</filename> i.e. user's default directory.
<userinput><code>pip install tarantool\>0.4 --user</code></userinput> to install in <filename>~</filename> i.e. user's default directory.
The program is assuming that the server (tarantool) is running on localhost (127.0.0.1) and its listen address is
the default (local host, port 3301) and space99's primary key type is string (box.space.space99.index['primary'].key_field[1].type = "STR")
the default (local host, port 3301) and space99's primary key type is string (box.space.space99.index[0].parts[1].type = "STR")
and user 'guest' has permission to read and write on space99. An administrator could fulfill all those conditions by
starting the tarantool server and executing these requests:<programlisting>
box.cfg{listen = 3301}
......@@ -379,32 +286,16 @@ box.schema.user.grant('guest', 'read,write', 'space', 'space99')</programlisting
The program will connect to the server, will send the request, and will not throw an exception if all went well.
If the tuple already exists, the program will throw DatabaseException(“Duplicate key exists in unique index”).
</para>
<programlisting language="python">
#!/usr/bin/python
from tarantool import Connection
c = Connection("127.0.0.1", 3301)
result = c.insert("space99",('First Tuple','Value', 'Value'))
print result
</programlisting>
<para>
The example program only shows one request and does not show all that's necessary for
good practice. For that, please see
<link xlink:href="http://tarantool-python.readthedocs.org/en/latest/"><filename>http://tarantool-python.readthedocs.org/en/latest/</filename></link>.
good practice. For that, see
<link xlink:href="http://github.com/tarantool/tarantool-python"><filename>http://github.com/tarantool/tarantool-python</filename></link>.
For an example of a Python API for <link xlink:href="https://github.com/tarantool/queue">Queue managers on Tarantool</link>, see
<link xlink:href="https://github.com/tarantool/tarantool-queue-python"><filename>https://github.com/tarantool/tarantool-queue-python</filename></link>.
</para>
</section>
<section xml:id="connector-ruby">
<title>Ruby</title>
<para>
You need <emphasis role="strong">Ruby 1.9</emphasis> or later
to use this connector. Connector sources are located in <link
xlink:href="https://github.com/mailru/tarantool-ruby"><filename>http://github.com/mailru/tarantool-ruby</filename></link>.
</para>
</section>
</chapter>
<!--
......
......@@ -329,7 +329,7 @@ server on the same processor without ill effects.
Since not all Tarantool operations can be expressed with the
data-manipulation functions, or with Lua, to gain
complete access to data manipulation functionality one must use
a <olink targetptr="connectors">Perl, Python, Ruby or other
a <olink targetptr="connectors">Perl, PHP, Python or other
programming language connector</olink>. The client/server
protocol is open and documented: an annotated BNF can be found
in the source tree, file <filename
......
......@@ -1296,7 +1296,7 @@ console.delimiter('')!
<varlistentry>
<term>
<emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>.key_field</emphasis>
<emphasis role="lua">box.space.<replaceable>space-name</replaceable>.index.<replaceable>index-name</replaceable>.parts</emphasis>
</term>
<listitem>
<para>
......
......@@ -207,6 +207,208 @@ Explanatory notes about what tarantool displayed in the above example:
</section>
<section xml:id="dist.lua">
<title>Utility <code>dist.lua</code></title>
<para>
With dist.lua one can say: "start an instance of the
Tarantool server which runs a single user-written Lua
program, allocating disk resources specifically for
that program, via a standardized deployment method."
If Tarantool was downloaded from source, then the script
is in ~/extra/dist/dist.lua. If Tarantool was installed
with debian or Red Hat installation packages, the script
is renamed <code>tarantoolctl</code> and is in
/usr/bin/tarantoolctl. The script handles such things as:
starting, stopping, rotating logs, logging in to the
application's console, and checking status.
</para>
<bridgehead renderas="sect4">configuring for dist.lua</bridgehead>
<para>
The dist.lua script will read a configuration file
named /etc/sysconfig/tarantool, or /etc/default/tarantool.
Most of the settings are similar to the settings
used by <code>box.cfg{...}</code>; however, dist.lua
adjusts some of them by adding an application name.
A copy of /etc/sysconfig/tarantool, with defaults for
all settings, would look like this:<programlisting>
default_cfg = {
pid_file = "/var/run/tarantool",
wal_dir = "/var/ lib / tarantool",
snap_dir = "/var/lib/tarantool",
sophia_dir = "/var/lib/tarantool",
logger = "/var/log/tarantool",
username = "tarantool",
}
instance_dir = "/etc/tarantool/instances.enabled"</programlisting>
</para>
<para>
The settings in the above script are:
</para>
<para>
pid_file = The directory for the pid file and control-socket file.
The script will add "/<replaceable>instance-name</replaceable>" to the directory name.
</para>
<para>
wal_dir = The directory for the write-ahead *.xlog files.
The script will add "/<replaceable>instance-name</replaceable>" to the directory-name.
</para>
<para>
snap_dir = The directory for the snapshot *.snap files.
The script will add "/<replaceable>instance-name</replaceable>" to the directory-name.
</para>
<para>
sophia_dir = The directory for the Sophia-storage-engine files.
The script will add "/sophia/<replaceable>instance-name</replaceable>" to the directory-name.
</para>
<para>
logger = The place where the application log will go.
The script will add /<replaceable>instance-name</replaceable>.log" to the name.
</para>
<para>
username = the user that runs the tarantool server.
</para>
<para>
instance_dir = the directory where all applications for this host are stored.
The user who writes an application for dist.lua must put the application's
source code in this directory, or a symbolic link. For examples in this section the application
name <code>my_app</code> will be used, and its source will have to be in
<code><replaceable>instance_dir</replaceable>/my_app.lua</code>.
</para>
<bridgehead renderas="sect4">commands for dist.lua</bridgehead>
<para>
The command format is <code>dist.lua <replaceable>operation</replaceable> application-name</code>,
where <replaceable>operation</replaceable> is one of: <code>start</code>, <code>stop</code>,
<code>status</code>, <code>logrotate</code>, <code>enter</code>. Thus ...<programlisting>
dist.lua start my_app -- starts application my_app
dist.lua stop my_app -- stops my_app
dist.lua enter my_app -- show my_app's admin console, if it has one
dist.lua logrotate my_app -- rotate my_app's log files (make new, remove old)
dist.lua status my_app -- check my_app's status</programlisting>
</para>
<bridgehead renderas="sect4">typical code snippets for dist.lua</bridgehead>
<para>
A user can check whether my_app is running with these lines:<programlisting>
if dist.lua status my_app; then
...
fi</programlisting>
A user can initiate, for boot time, an init.d set of instructions:<programlisting>
for (each file mentioned in the instance_dir directory):
dist.lua start `basename $ file .lua`</programlisting>
A user can set up a further configuration file for log rotation, like this:<programlisting>
/path/to/tarantool/*.log {
daily
size 512k
missingok
rotate 10
compress
delaycompress
create 0640 tarantool adm
postrotate
/path/to/dist.lua logrotate `basename $ 1 .log`
endscript
}</programlisting>
</para>
<bridgehead renderas="sect4">A detailed example for dist.lua</bridgehead>
<para>
The example's objective is: make a temporary directory
where dist.lua can start a long-running application
and monitor it.
</para>
<para>
The assumptions are: the root password is known,
the computer is only being used for tests,
the Tarantool server is ready to run but is
not currently running, and
there currently is no directory named tarantool_test.
</para>
<para>
Create a directory named /tarantool_test:<programlisting>
sudo mkdir /tarantool_test</programlisting>
</para>
<para>
Copy dist.lua to /tarantool_test.
If you made a source download to ~/tarantool-master, then<programlisting>
sudo cp ~/tarantool-master/extra/dist/dist.lua /tarantool_test/dist.lua</programlisting>
If the file was named tarantoolctl and placed on /usr/bin/tarantoolctl, then<programlisting>
sudo cp /usr/bin/tarantoolctl /tarantool_test/dist.lua</programlisting>
</para>
<para>
Check and possibly change the first line of /tarantool_test/dist.lua.
Initially it says<programlisting>
#!/usr/bin/env tarantool</programlisting>
If that is not correct, edit dist.lua and change the line.
For example, if the Tarantool server is actually on
/home/user/tarantool-master/src/tarantool, change the line to<programlisting>
#!/usr/bin/env /home/user/tarantool-master/src/tarantool</programlisting>
</para>
<para>
Save a copy of /etc/sysconfig/tarantool, if it exists.
</para>
<para>
Edit /etc/sysconfig/tarantool.
It might be necessary to say sudo mkdir /etc/sysconfig first.
Let the new file contents be:<programlisting>
default_cfg = {
pid_file = "/tarantool_test/my_app.pid",
wal_dir = "/tarantool_test",
snap_dir = "/tarantool_test",
sophia_dir = "/tarantool_test",
logger = "/tarantool_test/log",
username = "tarantool",
}
instance_dir = "/tarantool_test"</programlisting>
</para>
<para>
Make the my_app application file, that is, /tarantool_test/my_app.lua.
Let the file contents be:<programlisting>
box.cfg{listen = 3301}
box.schema.user.passwd('Gx5!')
box.schema.user.grant('guest','read,write,execute','universe')
fiber = require('fiber')
box.schema.create_space('tester')
box.space.tester:create_index('primary',{})
i = 0
while 0 == 0 do
fiber.sleep(5)
i = i + 1
print('insert ' .. i)
box.space.tester:insert{i, 'my_app tuple'}
end</programlisting>
</para>
<para>
Tell dist.lua to start the application ...<programlisting>
cd /tarantool_test
sudo ./dist.lua start my_app</programlisting>
... expect to see messages indicating that the instance has started. Then ...<programlisting>
ls -l /tarantool_test/my_app</programlisting>
... expect to see the .snap file, .xlog file, and sophia directory. Then ...<programlisting>
less /tarantool_test/log/my_app.log</programlisting>
... expect to see the contents of my_app's log, including error messages, if any. Then ...<programlisting>
cd /tarantool_test
#assume that 'tarantool' invokes the tarantool server
sudo tarantool
box.cfg{}
console = require('console')
console.connect('localhost:3301')
box.space.tester:select({0},{iterator='GE'})</programlisting>
... expect to see several tuples that my_app has created.
</para>
<para>
Stop. The only clean way to stop my_app is with dist_lua, thus:<programlisting>
sudo ./dist.lua stop my_app</programlisting>
</para>
<para>
Clean up. Restore the original contents of /etc/sysconfig/tarantool, and ...<programlisting>
cd /
sudo rm -R tarantool_test</programlisting>
</para>
</section>
<section xml:id="os-install-notes">
<title>System-specific administration notes</title>
<blockquote><para>
......
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