diff --git a/doc/sphinx/_static/sphinx_design.css b/doc/sphinx/_static/sphinx_design.css index a15df5eb80652b3d3afae8723427ff880bc57384..561029a5fa71780a9f292ecb5706e44608ccd019 100644 --- a/doc/sphinx/_static/sphinx_design.css +++ b/doc/sphinx/_static/sphinx_design.css @@ -519,3 +519,43 @@ ul.first.last.simple { .toctree-l1 li { list-style-type: none; } + +table.left-align-column-1 td { + text-align: left +} + +table.left-align-column-2 td + td { + text-align: left +} + + +table.left-align-column-3 td + td + td { + text-align: left +} + + +table.left-align-column-4 td + td + td + td { + text-align: left +} + + +table.right-align-column-1 td { + text-align: right +} + +table.right-align-column-2 td + td { + text-align: right +} + +table.right-align-column-3 td + td + td { + text-align: right +} + +table.right-align-column-4 td + td + td +td { + text-align: right +} + + + + + diff --git a/doc/sphinx/book/administration.rst b/doc/sphinx/book/administration.rst index 693d54007756c5ad5619dc0a9f853c42ed2de71d..9a6ee7fd5a30f349ba67d07a738c43c5db935edd 100644 --- a/doc/sphinx/book/administration.rst +++ b/doc/sphinx/book/administration.rst @@ -525,3 +525,417 @@ in the search box. There are no known permanent issues. For transient issues, go to http://github.com/tarantool/tarantool/issues and enter "OS X" in the search box. + +===================================================================== + Notes for systemd users +===================================================================== + +The Tarantool package fully supports :program:`systemd` for managing instances and +supervising database daemons. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Instance management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tarantool package was designed to have multiple running instances of Tarantool +on the same machine. Use :samp:`systemctl {start|stop|restart|status} tarantool@${MYAPP}` +to manage your databases and Lua applications. + +****************************************************** + creating instances +****************************************************** + +Simply put your Lua configuration to :file:`/etc/tarantool/instances.available/${MYAPP}.lua`: + +.. code-block:: lua + + box.cfg{listen = 3313} + require('myappcode').start() + +(this minimal example is sufficient). + +Another starting point could be the :file:`example.lua` script that ships with Tarantool +and defines all options. + +****************************************************** + starting instances +****************************************************** + +Use :samp:`systemctl start tarantool@${MYAPP}` to start ``${MYAPP}`` instance: + +.. code-block:: console + + $ systemctl start tarantool@example + $ ps axuf|grep exampl[e] + taranto+ 5350 1.3 0.3 1448872 7736 ? Ssl 20:05 0:28 tarantool example.lua <running> + +(console examples here and further on are for Fedora). + +Use :samp:`systemctl enable tarantool@${MYAPP}` to enable ``${MYAPP}`` instance +for auto-load during system startup. + +****************************************************** + monitoring instances +****************************************************** + +Use :samp:`systemctl status tarantool@${MYAPP}` to check information about +``${MYAPP}`` instance: + +.. code-block:: console + + $ systemctl status tarantool@example + tarantool@example.service - Tarantool Database Server + Loaded: loaded (/etc/systemd/system/tarantool@.service; disabled; vendor preset: disabled) + Active: active (running) + Docs: man:tarantool(1) + Process: 5346 ExecStart=/usr/bin/tarantoolctl start %I (code=exited, status=0/SUCCESS) + Main PID: 5350 (tarantool) + Tasks: 11 (limit: 512) + CGroup: /system.slice/system-tarantool.slice/tarantool@example.service + + 5350 tarantool example.lua <running> + +Use :samp:`journalctl -u tarantool@${MYAPP}` to check the boot log: + +.. code-block:: console + + $ journalctl -u tarantool@example -n 5 + -- Logs begin at Fri 2016-01-08 12:21:53 MSK, end at Thu 2016-01-21 21:17:47 MSK. -- + Jan 21 21:17:47 localhost.localdomain systemd[1]: Stopped Tarantool Database Server. + Jan 21 21:17:47 localhost.localdomain systemd[1]: Starting Tarantool Database Server... + Jan 21 21:17:47 localhost.localdomain tarantoolctl[5969]: /usr/bin/tarantoolctl: Found example.lua in /etc/tarantool/instances.available + Jan 21 21:17:47 localhost.localdomain tarantoolctl[5969]: /usr/bin/tarantoolctl: Starting instance... + Jan 21 21:17:47 localhost.localdomain systemd[1]: Started Tarantool Database Server + +****************************************************** + attaching to instances +****************************************************** + +You can attach to a running Tarantool instance and evaluate some Lua code using the +:program:`tarantoolctl` utility: + +.. code-block:: console + + $ tarantoolctl enter example + /bin/tarantoolctl: Found example.lua in /etc/tarantool/instances.available + /bin/tarantoolctl: Connecting to /var/run/tarantool/example.control + /bin/tarantoolctl: connected to unix/:/var/run/tarantool/example.control + unix/:/var/run/tarantool/example.control> 1 + 1 + --- + - 2 + ... + unix/:/var/run/tarantool/example.control> + +****************************************************** + checking logs +****************************************************** + +Tarantool logs important events to :file:`/var/log/tarantool/${MYAPP}.log`. + +Let's write something to the log file: + +.. code-block:: console + + $ tarantoolctl enter example + /bin/tarantoolctl: Found example.lua in /etc/tarantool/instances.available + /bin/tarantoolctl: Connecting to /var/run/tarantool/example.control + /bin/tarantoolctl: connected to unix/:/var/run/tarantool/example.control + unix/:/var/run/tarantool/example.control> require('log').info("Hello for README.systemd readers") + --- + ... + +Then check the logs: + +.. code-block:: console + + $ tail /var/log/tarantool/example.log + 2016-01-21 21:09:45.982 [5914] iproto I> binary: started + 2016-01-21 21:09:45.982 [5914] iproto I> binary: bound to 0.0.0.0:3301 + 2016-01-21 21:09:45.983 [5914] main/101/tarantoolctl I> ready to accept requests + 2016-01-21 21:09:45.983 [5914] main/101/example I> Run console at /var/run/tarantool/example.control + 2016-01-21 21:09:45.984 [5914] main/101/example I> tcp_server: remove dead UNIX socket: /var/run/tarantool/example.control + 2016-01-21 21:09:45.984 [5914] main/104/console/unix/:/var/run/tarant I> started + 2016-01-21 21:09:45.985 [5914] main C> entering the event loop + 2016-01-21 21:14:43.320 [5914] main/105/console/unix/: I> client unix/: connected + 2016-01-21 21:15:07.115 [5914] main/105/console/unix/: I> Hello for README.systemd readers + 2016-01-21 21:15:09.250 [5914] main/105/console/unix/: I> client unix/: disconnected + +Log rotation is enabled by default if you have :program:`logrotate` installed. Please configure +:file:`/etc/logrotate.d/tarantool` to change the default behavior. + +****************************************************** + stopping instances +****************************************************** + +Use :samp:`systemctl stop tarantool@${MYAPP}` to see information about the running +``${MYAPP}`` instance. + +.. code-block:: console + + $ systemctl stop tarantool@example + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Daemon supervision +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All instances are automatically restarted by :program:`systemd` in case of failure. + +Let's try to destroy an instance: + +.. code-block:: console + + $ systemctl status tarantool@example|grep PID + Main PID: 5885 (tarantool) + $ tarantoolctl enter example + /bin/tarantoolctl: Found example.lua in /etc/tarantool/instances.available + /bin/tarantoolctl: Connecting to /var/run/tarantool/example.control + /bin/tarantoolctl: connected to unix/:/var/run/tarantool/example.control + unix/:/var/run/tarantool/example.control> os.exit(-1) + /bin/tarantoolctl: unix/:/var/run/tarantool/example.control: Remote host closed connection + +Now let's make sure that :program:`systemd` has revived our Tarantool instance: + +.. code-block:: console + + $ systemctl status tarantool@example|grep PID + Main PID: 5914 (tarantool) + +Finally, let's check the boot logs: + +.. code-block:: console + + $ journalctl -u tarantool@example -n 8 + -- Logs begin at Fri 2016-01-08 12:21:53 MSK, end at Thu 2016-01-21 21:09:45 MSK. -- + Jan 21 21:09:45 localhost.localdomain systemd[1]: tarantool@example.service: Unit entered failed state. + Jan 21 21:09:45 localhost.localdomain systemd[1]: tarantool@example.service: Failed with result 'exit-code'. + Jan 21 21:09:45 localhost.localdomain systemd[1]: tarantool@example.service: Service hold-off time over, scheduling restart. + Jan 21 21:09:45 localhost.localdomain systemd[1]: Stopped Tarantool Database Server. + Jan 21 21:09:45 localhost.localdomain systemd[1]: Starting Tarantool Database Server... + Jan 21 21:09:45 localhost.localdomain tarantoolctl[5910]: /usr/bin/tarantoolctl: Found example.lua in /etc/tarantool/instances.available + Jan 21 21:09:45 localhost.localdomain tarantoolctl[5910]: /usr/bin/tarantoolctl: Starting instance... + Jan 21 21:09:45 localhost.localdomain systemd[1]: Started Tarantool Database Server. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Customizing the service file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Please don't modify the :file:`tarantool@.service` file in-place, because it will be +overwritten during package upgrades. It is recommended to copy this file to +:file:`/etc/systemd/system` and then modify the required settings. Alternatively, +you can create a directory named :file:`unit.d/` within :file:`/etc/systemd/system` and +put there a drop-in file :file:`name.conf` that only changes the required settings. +Please see ``systemd.unit(5)`` manual page for additional information. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Debugging +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:program:`coredumpctl` automatically saves core dumps and stack traces in case of a crash. +Here is how it works: + +.. code-block:: console + + $ # !!! please never do this on the production system !!! + $ tarantoolctl enter example + /bin/tarantoolctl: Found example.lua in /etc/tarantool/instances.available + /bin/tarantoolctl: Connecting to /var/run/tarantool/example.control + /bin/tarantoolctl: connected to unix/:/var/run/tarantool/example.control + unix/:/var/run/tarantool/example.control> require('ffi').cast('char *', 0)[0] = 48 + /bin/tarantoolctl: unix/:/var/run/tarantool/example.control: Remote host closed connection + +:samp:`coredumpctl list /usr/bin/tarantool` displays the latest crashes of the Tarantool daemon: + +.. code-block:: console + + $ coredumpctl list /usr/bin/tarantool + MTIME PID UID GID SIG PRESENT EXE + Sat 2016-01-23 15:21:24 MSK 20681 1000 1000 6 /usr/bin/tarantool + Sat 2016-01-23 15:51:56 MSK 21035 995 992 6 /usr/bin/tarantool + +:samp:`coredumpctl info <pid>` shows the stack trace and other useful information: + +.. code-block:: console + + $ coredumpctl info 21035 + PID: 21035 (tarantool) + UID: 995 (tarantool) + GID: 992 (tarantool) + Signal: 6 (ABRT) + Timestamp: Sat 2016-01-23 15:51:42 MSK (4h 36min ago) + Command Line: tarantool example.lua <running> + Executable: /usr/bin/tarantool + Control Group: /system.slice/system-tarantool.slice/tarantool@example.service + Unit: tarantool@example.service + Slice: system-tarantool.slice + Boot ID: 7c686e2ef4dc4e3ea59122757e3067e2 + Machine ID: a4a878729c654c7093dc6693f6a8e5ee + Hostname: localhost.localdomain + Message: Process 21035 (tarantool) of user 995 dumped core. + + Stack trace of thread 21035: + #0 0x00007f84993aa618 raise (libc.so.6) + #1 0x00007f84993ac21a abort (libc.so.6) + #2 0x0000560d0a9e9233 _ZL12sig_fatal_cbi (tarantool) + #3 0x00007f849a211220 __restore_rt (libpthread.so.0) + #4 0x0000560d0aaa5d9d lj_cconv_ct_ct (tarantool) + #5 0x0000560d0aaa687f lj_cconv_ct_tv (tarantool) + #6 0x0000560d0aaabe33 lj_cf_ffi_meta___newindex (tarantool) + #7 0x0000560d0aaae2f7 lj_BC_FUNCC (tarantool) + #8 0x0000560d0aa9aabd lua_pcall (tarantool) + #9 0x0000560d0aa71400 lbox_call (tarantool) + #10 0x0000560d0aa6ce36 lua_fiber_run_f (tarantool) + #11 0x0000560d0a9e8d0c _ZL16fiber_cxx_invokePFiP13__va_list_tagES0_ (tarantool) + #12 0x0000560d0aa7b255 fiber_loop (tarantool) + #13 0x0000560d0ab38ed1 coro_init (tarantool) + ... + +:samp:`coredumpctl -o filename.core info <pid>` saves the core dump into a file. + +:samp:`coredumpctl gdb <pid>` starts :program:`gdb` on the core dump. + +It is highly recommended to install the ``tarantool-debuginfo`` package to improve +:program:`gdb` experience. Example: + +.. code-block:: console + + $ dnf debuginfo-install tarantool + +.. $ # for CentOS +.. $ yum install tarantool-debuginfo + +:program:`gdb` also provides information about the ``debuginfo`` packages you need to install: + +.. code-block:: console + + $ # gdb -p <pid> + ... + Missing separate debuginfos, use: dnf debuginfo-install + glibc-2.22.90-26.fc24.x86_64 krb5-libs-1.14-12.fc24.x86_64 + libgcc-5.3.1-3.fc24.x86_64 libgomp-5.3.1-3.fc24.x86_64 + libselinux-2.4-6.fc24.x86_64 libstdc++-5.3.1-3.fc24.x86_64 + libyaml-0.1.6-7.fc23.x86_64 ncurses-libs-6.0-1.20150810.fc24.x86_64 + openssl-libs-1.0.2e-3.fc24.x86_64 + +Symbol names are present in stack traces even if you don't have the ``tarantool-debuginfo`` package installed. + +For additional information, please refer to the documentation provided with your Linux distribution. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Precautions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Please don't use ``tarantoolctl {start,stop,restart}`` to control instances + started by :program:`systemd`. It is still possible to use :program:`tarantoolctl` to start and + stop instances from your local directories (e.g. :file:`${HOME}`) without obtaining ``ROOT`` access. + +* :program:`tarantoolctl` is configured to work properly with ;program:`systemd`. Please don't + modify system-wide settings of :program:`tarantoolctl`, such as paths, directory permissions and usernames. + Otherwise, you have a chance to shoot yourself in the foot. + +* :program:`systemd` scripts are maintained by the Tarantool Team (http://tarantool.org). + Please file tickets directly to the upstream's bug tracker rather than to your Linux distribution. + +===================================================================== + Updating Tarantool in production +===================================================================== + +First, put your application's business logic in a Tarantool-Lua module that exports its functions for CALL. + +For example, :file:`/usr/share/tarantool/myapp.lua`: + +.. code-block:: lua + + local function start() + -- Initial version + box.once("myapp:.1.0", function() + box.schema.space.create("somedata") + box.space.somedata:create_index("primary") + ... + end + + -- migration code from 1.0 to 1.1 + box.once("myapp:.v1.1", function() + box.space.somedata.index.primary:alter(...) + ... + end + + -- migration code from 1.1 to 1.2 + box.once("myapp:.v1.2", function() + box.space.somedata.space:alter(...) + box.space.somedata:insert(...) + ... + end + + -- start some background fibers if you need + + local function stop() + -- stop all background fibers and cleanup resources + end + + local function api_for_call(xxx) + -- do some business + end + + return { + start = start; + stop = stop; + api_for_call = api_for_call; + } + +This file is maintained by the application's developers. On its side, +Tarantool Team provides templates for you to `assemble deb/rpm packages`_ +and utilities to quickly `assemble packages for specific platforms`_. +If needed, you can split applications into standalone files and/or modules. + +.. _assemble deb/rpm packages: https://github.com/tarantool/modulekit +.. _assemble packages for specific platforms: https://github.com/tarantool/build + + +Second, put an initialization script to the :file:`/etc/tarantool/instances.available` directory. + +For example, :file:`/etc/tarantool/instances.available/myappcfg.lua`: + +.. code-block:: lua + + #!/usr/bin/env tarantool + + box.cfg { + listen = 3301; + } + + if myapp ~= nil then + -- hot code reload using tarantoolctl or dofile() + + -- unload old application + myapp.stop() + -- clear cache for loaded modules and dependencies + package.loaded['myapp'] = nil + package.loaded['somedep'] = nil; -- dependency of 'myapp' + end + + -- load a new version of app and all dependencies + myapp = require('myapp').start({some app options controlled by sysadmins}) + + +As a more detailed example, you can take the :file:`example.lua` script that ships with Tarantool +and defines all configuration options. + +This initialization script is actually a configuration file and should be maintained by system +administrators, while developers only provide a template. + + +Now update your app file in :file:`/usr/share/tarantool`. Replace your application file +(for example, :file:`/usr/share/tarantool/myapp.lua`) and manually reload +the :file:`myappcfg.lua` initialization script using :program:`tarantoolctl`: + +.. code-block:: console + + $ tarantoolctl eval /etc/tarantool/instance.enabled/myappcfg.lua + +After that, you need to manually flush the cache of ``package.loaded`` modules. + +For deb/rpm packages, you can add the ``tarantoolctl eval`` instruction directly into Tarantool's +specification in :file:`RPM.spec` and the :file:`/debian` directory. + +Finally, clients make a CALL to ``myapp.api_for_call`` and other API functions. + +In case of ``tarantool-http``, there is no need to start the binary protocol at all. diff --git a/doc/sphinx/book/app/d_plugins.rst b/doc/sphinx/book/app/d_plugins.rst index b0763c0b29029271dec6ee780f1f7cf196364c5b..2103ce827c6a40924628787c55b0010cb1f652d9 100644 --- a/doc/sphinx/book/app/d_plugins.rst +++ b/doc/sphinx/book/app/d_plugins.rst @@ -504,8 +504,10 @@ Example, creating a function which sets each option in a separate line: > local p = {} > p.host = 'widgets.com' > p.db = 'test' + > p.user = 'postgres' + > p.password = 'postgres' > local conn = pg.connect(p) - > return p + > return conn > end --- ... @@ -557,9 +559,9 @@ in the SQL statement. tarantool> conn:execute('select tablename from pg_tables') --- - - - table_name: ALL_PLUGINS - - table_name: pg_statistics - - table_name: pg_type + - - tablename: pg_statistic + - tablename: pg_type + - tablename: pg_authid <...> ... @@ -609,7 +611,7 @@ on /usr. The PostgreSQL server is already running on the local host 127.0.0.1. $ # them in all places. Insert a row in database postgres, and quit. $ psql -h 127.0.0.1 -p 5432 -U postgres -d postgres Password for user postgres: - psql (9.3.0, server 9.3.2) + psql (9.3.10) SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) Type "help" for help. @@ -654,15 +656,15 @@ on /usr. The PostgreSQL server is already running on the local host 127.0.0.1. $ # Change directory to a directory which can be used for $ # temporary tests. For this example we assume that the - $ # name of this directory is /home/pgulutzan/tarantool_sandbox. - $ # (Change "/home/pgulutzan" to whatever is the user's actual + $ # name of this directory is $HOME/tarantool_sandbox. + $ # (Change "$HOME" to whatever is the user's actual $ # home directory for the machine that's used for this test.) - cd /home/pgulutzan/tarantool_sandbox + cd $HOME/tarantool_sandbox $ # Start the Tarantool server. Do not use a Lua initialization file. $ tarantool - tarantool: version 1.6.6-222-g48b98bb + tarantool: version 1.6.8-412-g803b15c type 'help' for interactive help tarantool> @@ -688,9 +690,9 @@ Lua tutorial earlier in the Tarantool user manual. tarantool> function pg_select () > local conn = pg.connect({ > host = '127.0.0.1', - > port = 5432 - > user = 'postgres' - > password = 'postgres' + > port = 5432, + > user = 'postgres', + > password = 'postgres', > db = 'postgres' > }) > local test = conn:execute('SELECT * FROM test WHERE s1 = 1') diff --git a/doc/sphinx/book/box/atomic.rst b/doc/sphinx/book/box/atomic.rst index cadea351d5d3c7151a4d92bc08b535eeb50f6f48..0fd0152ddfbf309b85240f5160739e96de2bd492 100644 --- a/doc/sphinx/book/box/atomic.rst +++ b/doc/sphinx/book/box/atomic.rst @@ -1,43 +1,54 @@ +.. _atomic_execution: + ------------------------------------------------------------------------------- Atomic execution ------------------------------------------------------------------------------- -In several places in this manual it's been noted that Lua processes occur in fibers on a -single thread. That is why there can be a guarantee of execution atomicity. -That requires emphasis. +In several places in this manual it's been noted that Lua processes occur in +fibers on a single thread. That is why there can be a guarantee of execution +atomicity. That requires emphasis. + + +.. _cooperative_multitasking: =========================================================== Cooperative multitasking environment =========================================================== -Tarantool uses cooperative multi-tasking: unless a -running fiber deliberately yields control to some other fiber, it is not -preempted. “Yield points†are built into all calls from Tarantool core to the -operating system. Any system call which can block is performed in an -asynchronous manner and the fiber waiting on the system call is preempted with -a fiber ready to run. This model makes all programmatic locks unnecessary: -cooperative multitasking ensures that there will be no concurrency around a resource, -no race conditions and no memory consistency issues. - -When requests are small, e.g. simple UPDATE, INSERT, DELETE, SELECT, fiber -scheduling is fair: it takes only a little time to process the request, schedule -a disk write, and yield to a fiber serving the next client. - -A function, however, can perform complex computations, or be written in such a -way that control is not given away for a long time. This can lead to unfair +Tarantool uses cooperative multitasking: unless a running fiber deliberately +yields control, it is not preempted by some other fiber. But a running fiber +will deliberately yield when it encounters a "yield point": an explicit +`yield()` request, or an implicit yield due to an operating-system call. Any +system call which can block will be performed asynchronously, and any running +fiber which must wait for a system call will be preempted so that another +ready-to-run fiber takes its place and becomes the new running fiber. This model +makes all programmatic locks unnecessary: cooperative multitasking ensures that +there will be no concurrency around a resource, no race conditions, and +no memory consistency issues. + +When requests are small, for example simple UPDATE or INSERT or DELETE or SELECT, +fiber scheduling is fair: it takes only a little time to process the request, +schedule a disk write, and yield to a fiber serving the next client. + +However, a function might perform complex computations or might be written in +such a way that yields do not occur for a long time. This can lead to unfair scheduling, when a single client throttles the rest of the system, or to apparent stalls in request processing. Avoiding this situation is the -responsibility of the function's author. Most of the box calls, such as -:func:`box.space...insert <space_object.insert>`, -:func:`box.space...update <space_object.update>`, -:func:`box.space...delete <space_object.delete>` are yield points; +responsibility of the function's author. For the default memtx storage engine +most of the box calls, including the data-change requests +:func:`box.space...insert <space_object.insert>` or +:func:`box.space...update <space_object.update>` or +:func:`box.space...delete <space_object.delete>`, are yield points; however, :func:`box.space...select <space_object.select>` is not. -It should also be noted that, in the absence of transactions, any yield in a -function is a potential change in the database state. Effectively, it's only -possible to have CAS (compare-and-swap) -like atomic stored procedures: i.e. -functions which select and then modify a record. Multiple data change requests -always run through a built-in yield point. +Note re storage engine: sophia has different rules: insert or update or delete +will very rarely cause a yield, but select can cause a yield. + +In the absence of transactions, any function that contains yield points may see +changes in the database state caused by fibers that preempt. Then the only safe +atomic functions for memtx databases would be functions which contain only one +database request, or functions which contain a select request followed by a +data-change request. At this point an objection could arise: "It's good that a single data-change request will commit and yield, but surely there are times when multiple @@ -49,19 +60,19 @@ block was designed. .. function:: box.begin() - From this point, implicit yields are suspended. In effect the fiber which - executes ``box.begin()`` is starting an "active multi-request transaction", - blocking all other fibers until the transaction ends. All operations within - this transaction should use the same storage engine. + Begin the transaction. Disable implicit yields until the transaction ends. + Signal that writes to the write-ahead log will be deferred until the transaction ends. + In effect the fiber which executes ``box.begin()`` is starting an "active + multi-request transaction", blocking all other fibers. .. function:: box.commit() - End the currently active transaction, and make all its data-change + End the transaction, and make all its data-change operations permanent. .. function:: box.rollback() - End the currently active transaction, but cancel all its data-change + End the transaction, but cancel all its data-change operations. An explicit call to functions outside ``box.space`` that always yield, such as ``fiber.yield`` or ``fiber.sleep``, will have the same effect. @@ -70,6 +81,11 @@ It is not enough to enclose them between ``begin`` and ``commit`` or ``rollback` To ensure they are sent as a single block: put them in a function, or put them all on one line, or use a delimiter so that multi-line requests are handled together. +**All database operations in a transaction should use the same storage engine**. +It is not safe to access tuple sets that are defined with ``{engine='sophia'}`` +and also access tuple sets that are defined with ``{engine='memtx'}``, +in the same transaction. + =========================================================== Example =========================================================== diff --git a/doc/sphinx/book/box/authentication.rst b/doc/sphinx/book/box/authentication.rst index eaf292017e35fabd7347f340c21f3706837b4621..a52cdad10b5a57d515a0b22d854086ff0a97610d 100644 --- a/doc/sphinx/book/box/authentication.rst +++ b/doc/sphinx/book/box/authentication.rst @@ -65,6 +65,11 @@ There are four special tuples in the _user space: 'guest', 'admin', 'public', an .. container:: table + .. rst-class:: left-align-column-1 + .. rst-class:: right-align-column-2 + .. rst-class:: left-align-column-3 + .. rst-class:: left-align-column-4 + +-------------+----+------+--------------------------------------------------------+ | Name | ID | Type | Description | +=============+====+======+========================================================+ diff --git a/doc/sphinx/book/box/box_index.rst b/doc/sphinx/book/box/box_index.rst index 07b3c851bd6e239278b445a68bfe9eb5648073fc..fc2dd55b50847a61c6420858150077fc0e4c6614 100644 --- a/doc/sphinx/book/box/box_index.rst +++ b/doc/sphinx/book/box/box_index.rst @@ -115,6 +115,10 @@ API is a direct binding to corresponding methods of index objects of type Note re storage engine: sophia does not allow search-value-parts to be ``nil`` or missing. + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + .. rst-class:: left-align-column-3 + +---------------+-----------+---------------------------------------------+ | Type | Arguments | Description | +===============+===========+=============================================+ @@ -166,6 +170,10 @@ API is a direct binding to corresponding methods of index objects of type **Iterator types for HASH indexes** + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + .. rst-class:: left-align-column-3 + +---------------+-----------+------------------------------------------------+ | Type | Arguments | Description | +===============+===========+================================================+ @@ -195,6 +203,10 @@ API is a direct binding to corresponding methods of index objects of type **Iterator types for BITSET indexes** + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + .. rst-class:: left-align-column-3 + +----------------------------+-----------+----------------------------------------------+ | Type | Arguments | Description | +============================+===========+==============================================+ @@ -227,6 +239,10 @@ API is a direct binding to corresponding methods of index objects of type **Iterator types for RTREE indexes** + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + .. rst-class:: left-align-column-3 + +--------------------+-----------+---------------------------------------------------------+ | Type | Arguments | Description | +====================+===========+=========================================================+ diff --git a/doc/sphinx/book/box/box_schema.rst b/doc/sphinx/book/box/box_schema.rst index 87a8c291ee4bcef8b3f6a499e4e3f996dc6e9431..7c2bde3e37ad5128b3c2b09507a93b2a2aca4cdb 100644 --- a/doc/sphinx/book/box/box_schema.rst +++ b/doc/sphinx/book/box/box_schema.rst @@ -25,6 +25,11 @@ for spaces, users, roles, and function tuples. **Options for box.schema.space.create** + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + .. rst-class:: left-align-column-3 + .. rst-class:: left-align-column-4 + +---------------+--------------------+---------+---------------------+ | Name | Effect | Type | Default | +===============+====================+=========+=====================+ @@ -102,19 +107,21 @@ available for insert, select, and all the other :mod:`box.space` functions. box.schema.user.create('Lena', {password = 'X'}) box.schema.user.create('Lena', {if_not_exists = false}) -.. function:: box.schema.user.drop(user-name) +.. function:: box.schema.user.drop(user-name [, {options} ]) Drop a user. For explanation of how Tarantool maintains user data, see section :ref:`Users and the _user space <authentication-users>`. :param string user-name: the name of the user + :param table options: if_exists **Example:** .. code-block:: lua box.schema.user.drop('Lena') + box.schema.user.drop('Lena',{if_exists=false}) .. function:: box.schema.user.exists(user-name) diff --git a/doc/sphinx/book/box/box_space.rst b/doc/sphinx/book/box/box_space.rst index f268efe106a512239332146500989f18cdc6664e..f6c11978103a55d007eaa6c491fb87f17d4aaecb 100644 --- a/doc/sphinx/book/box/box_space.rst +++ b/doc/sphinx/book/box/box_space.rst @@ -63,6 +63,11 @@ A list of all ``box.space`` functions follows, then comes a list of all Options for ``space_object:create_index``: + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + .. rst-class:: left-align-column-3 + .. rst-class:: left-align-column-4 + +---------------+--------------------+-----------------------------+---------------------+ | Name | Effect | Type | Default | +===============+====================+=============================+=====================+ diff --git a/doc/sphinx/book/box/index.rst b/doc/sphinx/book/box/index.rst index c4dde6d29ce399e834adf1ecb055a0bd23b6bdb8..020c3a52f845b512ace7bb07c2c83f1e10dd21a6 100644 --- a/doc/sphinx/book/box/index.rst +++ b/doc/sphinx/book/box/index.rst @@ -325,6 +325,8 @@ because after the UPDATE the transaction processor thread can switch to another fiber, and delete the tuple that was just updated. Note re storage engine: sophia handles yields differently, see :ref:`differences between memtx and sophia <sophia_diff>`. +Note re multi-request transactions: there is a way to delay yields, +see :ref:`Atomic execution <atomic_execution>`. Since locks don't exist, and disk writes only involve the write-ahead log, transactions are usually fast. Also the Tarantool server may not be using @@ -540,6 +542,9 @@ introspection (inspecting contents of spaces, accessing server configuration). **Complexity Factors that may affect data manipulation functions in the box library** + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + +-------------------+-----------------------------------------------------+ | Index size | The number of index keys is the same as the number | | | of tuples in the data set. For a TREE index, if | diff --git a/doc/sphinx/book/box/sophia_diff.rst b/doc/sphinx/book/box/sophia_diff.rst index 9bac36dd7f44230e8d542aee15c5dbd48fc0e4cb..d885306750b0950ebc1cb96d6133352d875bb1e8 100644 --- a/doc/sphinx/book/box/sophia_diff.rst +++ b/doc/sphinx/book/box/sophia_diff.rst @@ -55,7 +55,7 @@ It was explained :ref:`earlier <yields_must_happen>` that memtx does not "yield" on a select request, it yields only on data-change requests. However, sophia does yield on a select request, or on an equivalent such as get() or pairs(). This has significance - for cooperative multitasking. + for :ref:`cooperative multitasking <cooperative_multitasking>`. For more about sophia, see Appendix E :ref:`sophia <sophia>`. diff --git a/doc/sphinx/book/configuration/index.rst b/doc/sphinx/book/configuration/index.rst index 86665f903d6ac37d6a5d5be04b9c668c8923e90b..fcde70dcf5d58ac8333a487ed722b547c56cf782 100644 --- a/doc/sphinx/book/configuration/index.rst +++ b/doc/sphinx/book/configuration/index.rst @@ -87,6 +87,9 @@ If username:password is omitted, then 'guest' is assumed. Some examples: .. container:: table + .. rst-class:: left-align-column-1 + .. rst-class:: left-align-column-2 + +-----------------------------+------------------------------+ | URI fragment | Example | +=============================+==============================+ diff --git a/doc/sphinx/book/connectors/__c.rst b/doc/sphinx/book/connectors/__c.rst index eb3c16a832bddc9579de0f70b2dd017730f54087..dae2f0b947b71a7bb199dd6e5c4d7e9a5de484ef 100644 --- a/doc/sphinx/book/connectors/__c.rst +++ b/doc/sphinx/book/connectors/__c.rst @@ -33,13 +33,6 @@ space :code:`examples` via the high-level C API. tnt_stream_free(tnt); } -:ref:`SETUP <c_setup>`,|br| -:ref:`CONNECT <c_connect>`,|br| -:ref:`MAKE REQUEST <c_make_request>`,|br| -:ref:`SEND REQUEST <c_send_request>`,|br| -:ref:`GET REPLY <c_get_reply>`,|br| -:ref:`TEARDOWN <c_teardown>` - To prepare, paste the code into a file named example.c and install tarantool-c. One way to install tarantool-c (using Ubuntu) is: @@ -70,8 +63,6 @@ If the insert fails, the program will print "Insert failed" and an error number. Here are notes corresponding to comments in the example program. -.. _c_setup: - **SETUP:** The setup begins by creating a stream. .. code-block:: c @@ -93,8 +84,6 @@ Function description: `struct tnt_stream *tnt_net(struct tnt_stream *s)` `int tnt_set(struct tnt_stream *s, int option, variant option-value)` -.. _c_connect: - **CONNECT:** Now that the stream named ``tnt`` exists and is associated with a URI, this example program can connect to the server. @@ -114,8 +103,6 @@ The connect might fail for a variety of reasons, such as: the server is not running, or the URI contains an invalid password. If the connect fails, the return value will be -1. -.. _c_make_request: - **MAKE REQUEST:** Most requests require passing a structured value, such as the contents of a tuple. @@ -140,8 +127,6 @@ Function description: ssize_t tnt_object_format(struct tnt_stream \*s, const char \*fmt, ...) -.. _c_send_request: - **SEND REQUEST:** The database-manipulation requests are analogous to the requests in the box library. @@ -167,8 +152,6 @@ Function description: ssize_t tnt_update(struct tnt_stream \*s, uint32_t space, uint32_t index, struct tnt_stream \*key, struct tnt_stream \*ops) -.. _c_get_reply: - **GET REPLY:** For most requests the client will receive a reply containing some indication whether the result was successful, and a set of tuples. @@ -190,8 +173,6 @@ Function description: tnt->read_reply(struct tnt_stream \*s, struct tnt_reply \*r) void tnt_reply_free(struct tnt_reply \*r) -.. _c_teardown: - **TEARDOWN:** When a session ends, the connection that was made with tnt_connect() should be closed and the objects that were made in the setup should be destroyed. diff --git a/doc/sphinx/book/connectors/index.rst b/doc/sphinx/book/connectors/index.rst index 237701f69a3dfd8c8ac63e09719d199d849b8224..5a6f9bf0e9b52ad2d7b2ef9dc90bf82656813b6b 100644 --- a/doc/sphinx/book/connectors/index.rst +++ b/doc/sphinx/book/connectors/index.rst @@ -38,10 +38,15 @@ components is in file :ref:`iproto protocol`. .. container:: table + .. rst-class:: left-align-column-1 + .. rst-class:: right-align-column-2 + .. rst-class:: right-align-column-3 + .. rst-class:: right-align-column-4 + +---------------------------------+---------+---------+---------+---------+ | Component | Byte #0 | Byte #1 | Byte #2 | Byte #3 | +=================================+=========+=========+=========+=========+ - | code for insert | 2 | | | | + | code for insert | 02 | | | | +---------------------------------+---------+---------+---------+---------+ | rest of header | ... | ... | ... | ... | +---------------------------------+---------+---------+---------+---------+ diff --git a/doc/sphinx/dev_guide/building_from_source.rst b/doc/sphinx/dev_guide/building_from_source.rst index 74d9ed45b1afe28b593950767aa580e2c58892e5..207e0bdd1b3c4df91c59f80bcd3e22d974d1743e 100644 --- a/doc/sphinx/dev_guide/building_from_source.rst +++ b/doc/sphinx/dev_guide/building_from_source.rst @@ -205,7 +205,7 @@ This is the end of the list of steps to take for source downloads. For your added convenience, github.com has README files with example scripts: |br| `README.CentOS <https://github.com/tarantool/tarantool/blob/master/README.CentOS>`_ for CentOS 5.8, |br| `README.FreeBSD <https://github.com/tarantool/tarantool/blob/master/README.FreeBSD>`_ for FreeBSD 10.1, |br| -`README.MacOSX <https://github.com/tarantool/tarantool/blob/master/README.MacOSX>`_ for Mac OS X `Lion`, |br| +`README.MacOSX <https://github.com/tarantool/tarantool/blob/master/README.MacOSX>`_ for Mac OS X `El Capitan`, |br| `README.md <https://github.com/tarantool/tarantool/blob/master/README.md>`_ for generic GNU/Linux. |br| These example scripts assume that the intent is to download from the master branch, build the server (but not the documentation), and run tests after build. diff --git a/doc/sphinx/getting_started.rst b/doc/sphinx/getting_started.rst index 0a10d349185ad25fd480728d123245d5fc2d0f2c..38b4e38801ad7e5e8b42055489a6cfb8440d2061 100644 --- a/doc/sphinx/getting_started.rst +++ b/doc/sphinx/getting_started.rst @@ -200,7 +200,7 @@ Choose the package you want. You can install tarantool via Homebrew. It contains binaries for OS X 10.09 and higher. Simply use: -.. code-block:: session +.. code-block:: bash $ brew install tarantool ==> Downloading https://homebrew.bintray.com/bottles/tarantool-1.6.7-593.el_capitan.bottle.tar.gz diff --git a/doc/sphinx/reference/pickle.rst b/doc/sphinx/reference/pickle.rst index 6a084dc5433af5c5770e62096f72529487f08250..07f9ae0e710e42fc308c69d8814c662821462b97 100644 --- a/doc/sphinx/reference/pickle.rst +++ b/doc/sphinx/reference/pickle.rst @@ -14,6 +14,8 @@ **Format specifiers** + .. rst-class:: left-align-column-2 + +------+-------------------------------------------------+ | b, B | converts Lua variable to a 1-byte integer, | | | and stores the integer in the resulting string | diff --git a/doc/sphinx/reference/socket.rst b/doc/sphinx/reference/socket.rst index 6003e925aca014a39e4fad2a12df3abdc694c523..62091100f61eba738fd4e51173f0ff34f22867ea 100644 --- a/doc/sphinx/reference/socket.rst +++ b/doc/sphinx/reference/socket.rst @@ -21,62 +21,64 @@ are ``errno``, ``error``. **Socket functions** + .. rst-class:: left-align-column-2 + +----------------+---------------------------------------------------------------+ | Purposes | Names | +================+===============================================================+ - | | :func:`socket() <socket.__call>` | - | +---------------------------------------------------------------+ - | setup | :func:`socket.tcp_connect() <socket.tcp_connect>` | - | +---------------------------------------------------------------+ - | | :func:`socket.tcp_server() <socket.tcp_server>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:sysconnect() <socket_object.sysconnect>` | + | setup | :func:`socket() <socket.__call>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket.tcp_connect() <socket.tcp_connect>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket.tcp_server() <socket.tcp_server>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:sysconnect() <socket_object.sysconnect>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:send() <socket_object.send>` | + +----------------+---------------------------------------------------------------+ + | sending | :func:`socket_object:sendto() <socket_object.sendto>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:write() <socket_object.write>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:syswrite() <socket_object.syswrite>` | + +----------------+---------------------------------------------------------------+ + | receiving | :func:`socket_object:recv() <socket_object.recv>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:recvfrom() <socket_object.recvfrom>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:read() <socket_object.read>` | + +----------------+---------------------------------------------------------------+ + | flag setting | :func:`socket_object:nonblock() <socket_object.nonblock>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:setsockopt() <socket_object.setsockopt>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:linger() <socket_object.linger>` | + +----------------+---------------------------------------------------------------+ + | client/server | :func:`socket_object:listen() <socket_object.listen>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:accept() <socket_object.accept>` | + +----------------+---------------------------------------------------------------+ + | teardown | :func:`socket_object:shutdown() <socket_object.shutdown>` | + +----------------+---------------------------------------------------------------+ + | "" | :func:`socket_object:close() <socket_object.close>` | + +----------------+---------------------------------------------------------------+ + | error checking | :func:`socket_object:error() <socket_object.error>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket_object:send() <socket_object.send>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:sendto() <socket_object.sendto>` | - | sending +---------------------------------------------------------------+ - | | :func:`socket_object:write() <socket_object.write>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:syswrite() <socket_object.syswrite>` | + | "" | :func:`socket_object:errno() <socket_object.errno>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket_object:recv() <socket_object.recv>` | - | +---------------------------------------------------------------+ - | receiving | :func:`socket_object:recvfrom() <socket_object.recvfrom>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:read() <socket_object.read>` | + | information | :func:`socket.getaddrinfo() <socket.getaddrinfo>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket_object:nonblock() <socket_object.nonblock>` | - | +---------------------------------------------------------------+ - | flag setting | :func:`socket_object:setsockopt() <socket_object.setsockopt>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:linger() <socket_object.linger>` | + | "" | :func:`socket_object:getsockopt() <socket_object.getsockopt>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket_object:listen() <socket_object.listen>` | - | client/server +---------------------------------------------------------------+ - | | :func:`socket_object:accept() <socket_object.accept>` | + | "" | :func:`socket_object:peer() <socket_object.peer>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket_object:shutdown() <socket_object.shutdown>` | - | teardown +---------------------------------------------------------------+ - | | :func:`socket_object:close() <socket_object.close>` | + | "" | :func:`socket_object:name() <socket_object.name>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket_object:error() <socket_object.error>` | - | error checking +---------------------------------------------------------------+ - | | :func:`socket_object:errno() <socket_object.errno>` | + | state checking | :func:`socket_object:readable() <socket_object.readable>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket.getaddrinfo() <socket.getaddrinfo>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:getsockopt() <socket_object.getsockopt>` | - | information +---------------------------------------------------------------+ - | | :func:`socket_object:peer() <socket_object.peer>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:name() <socket_object.name>` | + | "" | :func:`socket_object:writable() <socket_object.writable>` | +----------------+---------------------------------------------------------------+ - | | :func:`socket_object:readable() <socket_object.readable>` | - | +---------------------------------------------------------------+ - | state checking | :func:`socket_object:writable() <socket_object.writable>` | - | +---------------------------------------------------------------+ - | | :func:`socket_object:wait() <socket_object.wait>` | + | "" | :func:`socket_object:wait() <socket_object.wait>` | +----------------+---------------------------------------------------------------+ Typically a socket session will begin with the setup functions, will set one diff --git a/doc/www/content/newsite/careers.yml b/doc/www/content/newsite/careers.yml index 51887e35a775d38fe35adf4a001edf7f3f4194da..03ff50d21ab8eaa8d18dc9b7a1ec4823197e36e3 100644 --- a/doc/www/content/newsite/careers.yml +++ b/doc/www/content/newsite/careers.yml @@ -86,8 +86,8 @@ blocks: This is a full-time position at Mail.Ru's Moscow headquarters, a large modern building near the "Airport" subway station. Duties include: - * construction and operation of a Tarantool-cluster-based public cloud - * construction and operation of a Tarantool-cluster-based private cloud + * construction and operation of a Tarantool-cluster-based public/private + cloud * ensuring trouble-free and fast operation to the satisfaction of customers and management * continuous improvement of the system as load increases and the number diff --git a/doc/www/theme/static/design.css b/doc/www/theme/static/design.css index 7e66c0d969249a9534cb3815c78729502fa42f35..001144cb058f2baeef3624d4d297bf99e3cc8826 100644 --- a/doc/www/theme/static/design.css +++ b/doc/www/theme/static/design.css @@ -533,6 +533,24 @@ h1, h2, h3, h4, h5 { .i-avito:before { background-image:url('/theme/design/logo_avito.png'); } +.i-qiwi { + width:120px; + height:60px; +} +.i-qiwi:after, +.i-qiwi:before { + background-image:url('/theme/design/logo_qiwi.png'); +} + +.i-wallarm { + width:130px; + height:63px; +} +.i-wallarm:after, +.i-wallarm:before { + background-image:url('/theme/design/logo_wallarm.png'); +} + .b-example .b-block-wrapper { padding:35px 0 35px 0; } diff --git a/doc/www/theme/static/design/logo_qiwi.png b/doc/www/theme/static/design/logo_qiwi.png new file mode 100644 index 0000000000000000000000000000000000000000..5d709eaabb02ae35ecf6577015c1eb882aaf4f9c Binary files /dev/null and b/doc/www/theme/static/design/logo_qiwi.png differ diff --git a/doc/www/theme/static/design/logo_wallarm.png b/doc/www/theme/static/design/logo_wallarm.png new file mode 100644 index 0000000000000000000000000000000000000000..a6de58a3f52f933597900124407701b99ec7dc32 Binary files /dev/null and b/doc/www/theme/static/design/logo_wallarm.png differ diff --git a/doc/www/theme/templates/index.html b/doc/www/theme/templates/index.html index e3fdf17d908892b4841668512fdaf05cd0e462e8..a9048c28af822dd5367469955db25666de536562 100644 --- a/doc/www/theme/templates/index.html +++ b/doc/www/theme/templates/index.html @@ -151,6 +151,14 @@ <div class="b-cols-item"> <a href="http://avito.ru" class="b-cust_logo i-avito"></a> </div> + <div class="b-cols-item-empty"> </div> + <div class="b-cols-item"> + <a href="http://qiwi.ru" class="b-cust_logo i-qiwi"></a> + </div> + <div class="b-cols-item-empty"> </div> + <div class="b-cols-item"> + <a href="http://wallarm.com" class="b-cust_logo i-wallarm"></a> + </div> </div> </div> </section> diff --git a/test/long_run/lua/finalizers.lua b/test/long_run/lua/finalizers.lua index 25641d2e385f40cca777f0d2770a8faef2bfc7cb..69146a3231fd1d0ac4884b23fac8cd7e46faff53 100644 --- a/test/long_run/lua/finalizers.lua +++ b/test/long_run/lua/finalizers.lua @@ -1,8 +1,4 @@ #!/usr/bin/env tarantool -env = require('test_run') -test_run = env.new() - -test_run:cmd("setopt delimiter ';'") function on_gc(t) end; @@ -12,14 +8,12 @@ function test_finalizers() local i = 1 local ffi = require('ffi') while true do - result[i] = ffi.gc(ffi.cast('void *', NULL), on_gc) + result[i] = ffi.gc(ffi.cast('void *', 0), on_gc) i = i + 1 end return "done" end; -test_run:cmd("setopt delimiter ''") - test_finalizers() test_finalizers()