Crate tarantool

source ·
Expand description

Tarantool C API bindings for Rust. This library contains the following Tarantool API’s:

Caution! The library is currently under development. API may be unstable until version 1.0 is released.

Features

  • net_box - Enables protocol implementation (enabled by default)
  • schema - Enables schema manipulation utils (WIP as for now)

Prerequisites

  • rustc 1.59 or newer
  • tarantool 2.2

Stored procedures

There are several ways Tarantool can call Rust code. It can use either a plugin, a Lua FFI module, or a stored procedure. In this file we only cover the third option, namely Rust stored procedures. Even though Tarantool always treats Rust routines just as “C functions”, we keep on using the “stored procedure” term as an agreed convention and also for historical reasons.

This tutorial contains the following simple steps:

  1. examples/easy - prints “hello world”;
  2. examples/harder - decodes a passed parameter value;
  3. examples/hardest - uses this library to do a DBMS insert;
  4. examples/read - uses this library to do a DBMS select;
  5. examples/write - uses this library to do a DBMS replace.

Our examples are a good starting point for users who want to confidently start writing their own stored procedures.

Example

After getting the prerequisites installed, follow these steps:

Create a Cargo project:

$ cargo init --lib

Add the following lines to Cargo.toml:

[package]
name = "easy"
version = "0.1.0"
edition = "2018"
# author, license, etc

[dependencies]
tarantool = "0.6.0" # (1)
serde = "1.0" # (2)

[lib]
crate-type = ["cdylib"] # (3)
  1. Add the tarantool library to the dependencies;
  2. Optionally add Serde to the dependencies. This is only required if you want to use Rust structures as tuple values (see this example);
  3. Compile the dynamic library.

Requests will be done using Tarantool as a client. Start Tarantool, and enter the following requests:

box.cfg{listen=3306}
box.schema.space.create('capi_test')
box.space.capi_test:create_index('primary')
net_box = require('net.box')
capi_connection = net_box:new(3306)

Note: create a space named capi_test and establish the connection named capi_connection to the same instance.

Leave the client running. It will be used to enter more requests later.

Edit the lib.rs file and add the following lines:

#[tarantool::proc]
fn easy() {
    println!("hello world");
}

#[tarantool::proc]
fn easy2() {
    println!("hello world -- easy2");
}

Compile the program:

$ cargo build

Start another shell. Change directory (cd) so that it is the same as the directory that the client is running in. Copy the compiled library from target/debug to the current directory and rename it to easy.so

Now go back to the client and execute these requests:

box.schema.func.create('easy', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'easy')
capi_connection:call('easy')

Consult the documentation of box.schema.func.create(), box.schema.user.grant() and conn:call() for more details.

The matter in hand is the capi_connection:call('easy') function, which has three features.

One is to find the ‘easy’ function, which is easy indeed since by default Tarantool looks inside the current directory for a file named easy.so.

Another is to call the ‘easy’ function. Since the easy() function in lib.rs begins with println!("hello world"), the words “hello world” will be printed in the terminal.

The third feature is to make sure the call was successful. Since the easy() function in lib.rs ends with return 0, there is no error message to display and therefore the request is over.

The result should look like this:

tarantool> capi_connection:call('easy')
hello world
---
- []
...

Now let’s call the other function in lib.rs - easy2(). This is almost the same as the easy() function, but with a difference: when the file name is not the same as the function name, we have to specify {file-name}.{function-name}.

box.schema.func.create('easy.easy2', {language = 'C'})
box.schema.user.grant('guest', 'execute', 'function', 'easy.easy2')
capi_connection:call('easy.easy2')

… and this time the result will be hello world -- easy2.

As you can see, calling a Rust function is as straightforward as it can be.

Re-exports

pub use tlua;
pub use error::Result;

Modules

The clock module returns time values derived from the Posix / C CLOCK_GETTIME function or equivalent.
Cooperative input/output
Error handling utils. See “failure” crate documentation for details
Сooperative multitasking module
Box: indices
Logging utils. See “log” crate documentation for details
The net_box module contains connector to remote Tarantool server instances via a network.
Box: sequences
Box: session
Box: spaces
Transaction management
Tuples

Macros

decimal!
Auto-generate enum that maps to a string.
Set the last error.
Update a tuple or index.
Upsert a tuple or index.

Functions

Create a new lua state with an isolated stack. The new state has access to all the global and tarantool data (Lua variables, tables, modules, etc.).

Type Definitions

Attribute Macros

#[tarantool::proc] is a macro attribute for creating stored procedure functions.