Tokyo Tyrant: network interface of Tokyo Cabinet

Copyright (C) 2007-2008 Mikio Hirabayashi
Last Update: Sat, 15 Mar 2008 16:29:20 +0900

Table of Contents

  1. Introduction
  2. Installation
  3. The Server Programs
  4. The Client Programs
  5. The Remote Database API
  6. Protocol
  7. Tutorial
  8. License

Introduction

Tokyo Tyrant is a package of network interface to the DBM called Tokyo Cabinet. Though the DBM has high performance, you might bother in case that multiple processes share the same database, or remote processes access the database. Thus, Tokyo Tyrant is provided for concurrent and remote connections to Tokyo Cabinet. It is composed of the server process managing a database and its access library for client applications.

The server features high concurrency due to thread-pool modeled implementation and the "epoll" mechanism of the modern Linux kernel. The server and its clients communicate with each other by simple binary protocol on TCP/IP. Protocols compatible with memcached and HTTP/1.1 are also supported so that almost all principal platforms and programming languages can use Tokyo Tyrant. High availability and high integrity are also featured due to hot such mechanisms as hot backup, update logging, and replication.

As for now, the server works on Linux only.


Installation

Install the latest version of Tokyo Cabinet beforehand and get the package of Tokyo Tyrant.

When an archive file of Tokyo Tyrant is extracted, change the current working directory to the generated directory and perform installation.

Run the configuration script.

./configure

Build programs.

make

Install programs. This operation must be carried out by the root user.

make install

When a series of work finishes, the following files will be installed.

/usr/local/include/ttutil.h
/usr/local/include/tculog.h
/usr/local/include/tcrdb.h
/usr/local/lib/libtokyotyrant.a
/usr/local/lib/libtokyotyrant.so.1.15.0
/usr/local/lib/libtokyotyrant.so.1
/usr/local/lib/libtokyotyrant.so
/usr/local/lib/pkgconfig/tokyotyrant.pc
/usr/local/bin/ttserver
/usr/local/bin/ttultest
/usr/local/bin/ttulmgr
/usr/local/bin/tcrtest
/usr/local/bin/tcrmttest
/usr/local/bin/tcrmgr
/usr/local/sbin/ttservctl
/usr/local/share/tokyotyrant/...
/usr/local/man/man1/...
/usr/local/man/man3/...

To test the server, perform the following command. To finish it, press Ctrl-C on the terminal.

ttserver

To test the client connecting to the above running server, perform the following command on another terminal.

make check

The Server Programs

ttserver

The command `ttserver' runs the server managing a database instance. Because the database is treated by the abstract API of Tokyo Cabinet, you can choose the scheme on start-up of the server. Supported schema are on-memory database, hash database, and B+ tree database. This command is used in the following format. `dbname' specifies the database name. If it is omitted, on-memory database is specified.

ttserver [-host name] [-port num] [-thnum num] [-tout num] [-dmn] [-pid path] [-log path] [-ld|-le] [-ulog path] [-ulim num] [-uas] [-sid num] [-mhost name] [-mport num] [-rts path] [dbname]

Options feature the following.

To terminate the server normally, send SIGINT or SIGTERM to the process. It is okay to press Ctrl-C on the controlling terminal. To restart the server, send SIGHUP to the process. If the port number is not more than 0, UNIX domain socket is used and the path of the socket file is specified by the host parameter. This command returns 0 on success, another on failure.

The naming convention of the database is specified by the abstract API of Tokyo Cabinet. If the name is "*", the database will be an on-memory database. If its suffix is ".tch", the database will be a hash database. If its suffix is ".tcb", the database will be a B+ tree database. If its suffix is ".tcf", the database will be a fixed-length database. Otherwise, this function fails. Tuning parameters can trail the name, separated by "#". Each parameter is composed of the name and the number, separated by "=". On-memory database supports "bnum", "capnum", and "capsiz". Hash database supports "mode", "bnum", "apow", "fpow", "opts", and "rcnum". B+ tree database supports "mode", "lmemb", "nmemb", "bnum", "apow", "fpow", "opts", "lcnum", and "ncnum". Fixed-length database supports "mode", "width", and "limsiz". "capnum" specifies the capacity number of records. "capsiz" specifies the capacity size of using memory. Records spilled the capacity are removed by the storing order. "mode" can contain "w" of writer, "r" of reader, "c" of creating, "t" of truncating, "e" of no locking, and "f" of non-blocking lock. The default mode is relevant to "wc". "opts" can contains "l" of large option, "d" of Deflate option, and "b" of TCBS option. "width" specifies the width of the value of each record. "limsiz" specifies the limit size of the database file. For example, "casket.tch#bnum=1000000#opts=ld" means that the name of the database file is "casket.tch", and the bucket number is 1000000, and the options are large and Deflate.

ttservctl

The command `ttservctl' is the startup script of the server. It can be called by the RC script of the bootstrap process of the operating system. This command is used in the following format.

ttservctl start
Startup the server.
ttservctl stop
Stop the server.
ttservctl restart
Restart the server.
ttservctl hup
Send HUP signal to the server for log rotation.

The database is placed as "/var/ttserver/casket.tch". The log and related files are also placed in "/var/ttserver". This command returns 0 on success, another on failure.

ttulmgr

The command `ttulmgr' is the utility to export and import the update log. It is useful to filter the update log with such text utilities as `grep' and `sed'. This command is used in the following format. `upath' specifies the update log directory.

ttulmgr export [-ts num] [-sid num] upath
Export the update log as TSV text data to the standard output.
ttulmgr import upath
Import TSV text data from the standard input to the update log.

Options feature the following.

This command returns 0 on success, another on failure.


The Client Programs

tcrtest

The command `tcrtest' is a utility for facility test and performance test. This command is used in the following format. `host' specifies the host name of the server. `rnum' specifies the number of iterations.

tcrtest write [-port num] [-cnum num] [-nr] [-rnd] host rnum
Store records with keys of 8 bytes. They change as `00000001', `00000002'...
tcrtest read [-port num] [-cnum num] [-mul num] [-rnd] host
Retrieve all records of the database above.
tcrtest remove [-port num] [-cnum num] [-rnd] host
Remove all records of the database above.
tcrtest rcat [-port num] [-cnum num] [-rtt num] host rnum
Store records with partway duplicated keys using concatenate mode.
tcrtest misc [-port num] [-cnum num] host rnum
Perform miscellaneous test of various operations.
tcrtest wicked [-port num] [-cnum num] host rnum
Perform updating operations of list and map selected at random.

Options feature the following.

If the port number is not more than 0, UNIX domain socket is used and the path of the socket file is specified by the host parameter. This command returns 0 on success, another on failure.

tcrmttest

The command `tcrmttest' is a utility for facility test under multi-thread situation. This command is used in the following format. `host' specifies the host name of the server. `rnum' specifies the number of iterations.

tcrmttest write [-port num] [-tnum num] [-nr] [-rnd] host rnum
Store records with keys of 8 bytes. They change as `00000001', `00000002'...
tcrmttest read [-port num] [-tnum num] [-mul num] host
Retrieve all records of the database above.
tcrmttest remove [-port num] [-tnum num] host
Remove all records of the database above.

Options feature the following.

If the port number is not more than 0, UNIX domain socket is used and the path of the socket file is specified by the host parameter. This command returns 0 on success, another on failure.

tcrmgr

The command `tcrmgr' is a utility for test and debugging of the remote database API and its applications. `host' specifies the host name of the server. `key' specifies the key of a record. `value' specifies the value of a record. `dpath' specifies the destination file. `upath' specifies the update log directory. `mhost' specifies the host name of the replication master. `url' specifies the target URL.

tcrmgr inform [-port num] [-st] host
Print miscellaneous information to the standard output.
tcrmgr put [-port num] [-sx] [-dk|-dc] host key value
Store a record.
tcrmgr out [-port num] [-sx] host key
Remove a record.
tcrmgr get [-port num] [-sx] [-px] [-pz] host key
Print the value of a record.
tcrmgr mget [-port num] [-sx] [-px] host [key...]
Print keys and values of multiple records.
tcrmgr list [-port num] [-m num] [-pv] [-px] [-fm str] host
Print keys of all records, separated by line feeds.
tcrmgr sync [-port num] host
Synchronize updated contents with the database file.
tcrmgr vanish [-port num] host
Remove all records.
tcrmgr copy [-port num] host dpath
Copy the database file.
tcrmgr restore [-port num] host upath
Restore the database with update log.
tcrmgr setmst [-port num] [-mport num] host [mhost]
Set the replication master.
tcrmgr repl [-port num] [-ts num] [-sid num] [-ph] host
Replicate the update log.
tcrmgr http [-ah name value] [-ih] url
Fetch the resource of a URL by HTTP.
tcrmgr version
Print the version information of Tokyo Tyrant.

Options feature the following.

If the port number is not more than 0, UNIX domain socket is used and the path of the socket file is specified by the host parameter. This command returns 0 on success, another on failure.


The Remote Database API

Remote database is a set of interfaces to use an abstract database of Tokyo Cabinet, mediated by a server of Tokyo Tyrant. See `tcrdb.h' for entire specification.

Description

To use the remote database API, include `tcrdb.h' and related standard header files. Usually, write the following description near the front of a source file.

#include <tcrdb.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

Objects whose type is pointer to `TCRDB' are used to handle remote databases. A remote database object is created with the function `tcrdbnew' and is deleted with the function `tcrdbdel'. To avoid memory leak, it is important to delete every object when it is no longer in use.

Before operations to store or retrieve records, it is necessary to connect the remote database object to the server. The function `tcrdbopen' is used to open a database connection and the function `tcrdbclose' is used to close the connection.

API

The function `tcrdberrmsg' is used in order to get the message string corresponding to an error code.

const char *tcrdberrmsg(int ecode);
`ecode' specifies the error code.
The return value is the message string of the error code.

The function `tcrdbnew' is used in order to create a remote database object.

TCRDB *tcrdbnew(void);
The return value is the new remote database object.

The function `tcrdbdel' is used in order to delete a remote database object.

void tcrdbdel(TCRDB *rdb);
`rdb' specifies the remote database object.

The function `tcrdbecode' is used in order to get the last happened error code of a remote database object.

int tcrdbecode(TCRDB *rdb);
`rdb' specifies the remote database object.
The return value is the last happened error code.
The following error code is defined: `TTESUCCESS' for success, `TTEINVALID' for invalid operation, `TTENOHOST' for host not found, `TTEREFUSED' for connection refused, `TTESEND' for send error, `TTERECV' for recv error, `TTEKEEP' for existing record, `TTENOREC' for no record found, `TTEMISC' for miscellaneous error.

The function `tcrdbopen' is used in order to open a remote database.

bool tcrdbopen(TCRDB *rdb, const char *host, int port);
`rdb' specifies the remote database object.
`host' specifies the name or the address of the server.
`port' specifies the port number.
If successful, the return value is true, else, it is false.

The function `tcrdbclose' is used in order to close a remote database object.

bool tcrdbclose(TCRDB *rdb);
`rdb' specifies the remote database object.
If successful, the return value is true, else, it is false.

The function `tcrdbput' is used in order to store a record into a remote database object.

bool tcrdbput(TCRDB *rdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
`vbuf' specifies the pointer to the region of the value.
`vsiz' specifies the size of the region of the value.
If successful, the return value is true, else, it is false.
If a record with the same key exists in the database, it is overwritten.

The function `tcrdbput2' is used in order to store a string record into a remote object.

bool tcrdbput2(TCRDB *rdb, const char *kstr, const char *vstr);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
`vstr' specifies the string of the value.
If successful, the return value is true, else, it is false.
If a record with the same key exists in the database, it is overwritten.

The function `tcrdbputkeep' is used in order to store a new record into a remote database object.

bool tcrdbputkeep(TCRDB *rdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
`vbuf' specifies the pointer to the region of the value.
`vsiz' specifies the size of the region of the value.
If successful, the return value is true, else, it is false.
If a record with the same key exists in the database, this function has no effect.

The function `tcrdbputkeep2' is used in order to store a new string record into a remote database object.

bool tcrdbputkeep2(TCRDB *rdb, const char *kstr, const char *vstr);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
`vstr' specifies the string of the value.
If successful, the return value is true, else, it is false.
If a record with the same key exists in the database, this function has no effect.

The function `tcrdbputcat' is used in order to concatenate a value at the end of the existing record in a remote database object.

bool tcrdbputcat(TCRDB *rdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
`vbuf' specifies the pointer to the region of the value.
`vsiz' specifies the size of the region of the value.
If successful, the return value is true, else, it is false.
If there is no corresponding record, a new record is created.

The function `tcrdbputcat2' is used in order to concatenate a string value at the end of the existing record in a remote database object.

bool tcrdbputcat2(TCRDB *rdb, const char *kstr, const char *vstr);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
`vstr' specifies the string of the value.
If successful, the return value is true, else, it is false.
If there is no corresponding record, a new record is created.

The function `tcrdbputrtt' is used in order to concatenate a value at the end of the existing record and rotate it to the left.

bool tcrdbputrtt(TCRDB *rdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz, int width);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
`vbuf' specifies the pointer to the region of the value.
`vsiz' specifies the size of the region of the value.
`width' specifies the width of the record.
If successful, the return value is true, else, it is false.
If there is no corresponding record, a new record is created.

The function `tcrdbputrtt2' is used in order to concatenate a string value at the end of the existing record and rotate it to the left.

bool tcrdbputrtt2(TCRDB *rdb, const char *kstr, const char *vstr, int width);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
`vstr' specifies the string of the value.
`width' specifies the width of the record.
If successful, the return value is true, else, it is false.
If there is no corresponding record, a new record is created.

The function `tcrdbputnr' is used in order to store a record into a remote database object without response from the server.

bool tcrdbputnr(TCRDB *rdb, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
`vbuf' specifies the pointer to the region of the value.
`vsiz' specifies the size of the region of the value.
If successful, the return value is true, else, it is false.
If a record with the same key exists in the database, it is overwritten.

The function `tcrdbputnr2' is used in order to store a string record into a remote object without response from the server.

bool tcrdbputnr2(TCRDB *rdb, const char *kstr, const char *vstr);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
`vstr' specifies the string of the value.
If successful, the return value is true, else, it is false.
If a record with the same key exists in the database, it is overwritten.

The function `tcrdbout' is used in order to remove a record of a remote database object.

bool tcrdbout(TCRDB *rdb, const void *kbuf, int ksiz);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
If successful, the return value is true, else, it is false.

The function `tcrdbout2' is used in order to remove a string record of a remote database object.

bool tcrdbout2(TCRDB *rdb, const char *kstr);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
If successful, the return value is true, else, it is false.

The function `tcrdbget' is used in order to retrieve a record in a remote database object.

void *tcrdbget(TCRDB *rdb, const void *kbuf, int ksiz, int *sp);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
`sp' specifies the pointer to the variable into which the size of the region of the return value is assigned.
If successful, the return value is the pointer to the region of the value of the corresponding record. `NULL' is returned if no record corresponds.
Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a character string. Because the region of the return value is allocated with the `malloc' call, it should be released with the `free' call when it is no longer in use.

The function `tcrdbget2' is used in order to retrieve a string record in a remote database object.

char *tcrdbget2(TCRDB *rdb, const char *kstr);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
If successful, the return value is the string of the value of the corresponding record. `NULL' is returned if no record corresponds.
Because the region of the return value is allocated with the `malloc' call, it should be released with the `free' call when it is no longer in use.

The function `tcrdbget3' is used in order to retrieve records in a remote database object.

bool tcrdbget3(TCRDB *rdb, TCMAP *recs);
`rdb' specifies the remote database object.
`recs' specifies a map object containing the retrieval keys. As a result of this function, keys existing in the database have the corresponding values and keys not existing in the database are removed.
If successful, the return value is true, else, it is false.

The function `tcrdbvsiz' is used in order to get the size of the value of a record in a remote database object.

int tcrdbvsiz(TCRDB *rdb, const void *kbuf, int ksiz);
`rdb' specifies the remote database object.
`kbuf' specifies the pointer to the region of the key.
`ksiz' specifies the size of the region of the key.
If successful, the return value is the size of the value of the corresponding record, else, it is -1.

The function `tcrdbvsiz2' is used in order to get the size of the value of a string record in a remote database object.

int tcrdbvsiz2(TCRDB *rdb, const char *kstr);
`rdb' specifies the remote database object.
`kstr' specifies the string of the key.
If successful, the return value is the size of the value of the corresponding record, else, it is -1.

The function `tcrdbiterinit' is used in order to initialize the iterator of a remote database object.

bool tcrdbiterinit(TCRDB *rdb);
`rdb' specifies the remote database object.
If successful, the return value is true, else, it is false.
The iterator is used in order to access the key of every record stored in a database.

The function `tcrdbiternext' is used in order to get the next key of the iterator of a remote database object.

void *tcrdbiternext(TCRDB *rdb, int *sp);
`rdb' specifies the remote database object.
`sp' specifies the pointer to the variable into which the size of the region of the return value is assigned.
If successful, the return value is the pointer to the region of the next key, else, it is `NULL'. `NULL' is returned when no record is to be get out of the iterator.
Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a character string. Because the region of the return value is allocated with the `malloc' call, it should be released with the `free' call when it is no longer in use. The iterator can be updated by multiple connections and then it is not assured that every record is traversed.

The function `tcrdbiternext2' is used in order to get the next key string of the iterator of a remote database object.

char *tcrdbiternext2(TCRDB *rdb);
`rdb' specifies the remote database object.
If successful, the return value is the string of the next key, else, it is `NULL'. `NULL' is returned when no record is to be get out of the iterator.
Because the region of the return value is allocated with the `malloc' call, it should be released with the `free' call when it is no longer in use. The iterator can be updated by multiple connections and then it is not assured that every record is traversed.

The function `tcrdbfwmkeys' is used in order to get forward matching keys in a remote database object.

TCLIST *tcrdbfwmkeys(TCRDB *rdb, const void *pbuf, int psiz, int max);
`rdb' specifies the remote database object.
`pbuf' specifies the pointer to the region of the prefix.
`psiz' specifies the size of the region of the prefix.
`max' specifies the maximum number of keys to be fetched. If it is negative, no limit is specified.
The return value is a list object of the corresponding keys. This function does never fail and return an empty list even if no key corresponds.
Because the object of the return value is created with the function `tclistnew', it should be deleted with the function `tclistdel' when it is no longer in use.

The function `tcrdbfwmkeys2' is used in order to get forward matching string keys in a remote database object.

TCLIST *tcrdbfwmkeys2(TCRDB *rdb, const char *pstr, int max);
`rdb' specifies the remote database object.
`pstr' specifies the string of the prefix.
`max' specifies the maximum number of keys to be fetched. If it is negative, no limit is specified.
The return value is a list object of the corresponding keys. This function does never fail and return an empty list even if no key corresponds.
Because the object of the return value is created with the function `tclistnew', it should be deleted with the function `tclistdel' when it is no longer in use.

The function `tcrdbsync' is used in order to synchronize updated contents of a remote database object with the file and the device.

bool tcrdbsync(TCRDB *rdb);
`rdb' specifies the remote database object.
If successful, the return value is true, else, it is false.
This function fails and has no effect for on-memory database.

The function `tcrdbvanish' is used in order to remove all records of a remote database object.

bool tcrdbvanish(TCRDB *rdb);
`rdb' specifies the remote database object.
If successful, the return value is true, else, it is false.

The function `tcrdbcopy' is used in order to copy the database file of a remote database object.

bool tcrdbcopy(TCRDB *rdb, const char *path);
`rdb' specifies the remote database object.
`path' specifies the path of the destination file. If it begins with `@', the trailing substring is executed as a command line.
If successful, the return value is true, else, it is false. False is returned if the executed command returns non-zero code.
The database file is assured to be kept synchronized and not modified while the copying or executing operation is in progress. So, this function is useful to create a backup file of the database file. This function fails and has no effect for on-memory database.

The function `tcrdbrestore' is used in order to restore the database file of a remote database object from the update log.

bool tcrdbrestore(TCRDB *rdb, const char *path, uint64_t ts);
`rdb' specifies the remote database object.
`path' specifies the path of the update log directory. If it begins with `+', the trailing substring is treated as the path and consistency checking is omitted.
`ts' specifies the beginning time stamp in microseconds.
If successful, the return value is true, else, it is false.

The function `tcrdbsetmst' is used in order to set the replication master of a remote database object from the update log.

bool tcrdbsetmst(TCRDB *rdb, const char *host, int port);
`rdb' specifies the remote database object.
`host' specifies the name or the address of the server. If it is `NULL', replication of the database is disabled.
`port' specifies the port number.
If successful, the return value is true, else, it is false.

The function `tcrdbrnum' is used in order to get the number of records of a remote database object.

uint64_t tcrdbrnum(TCRDB *rdb);
`rdb' specifies the remote database object.
The return value is the number of records or 0 if the object does not connect to any database server.

The function `tcrdbsize' is used in order to get the size of the database of a remote database object.

uint64_t tcrdbsize(TCRDB *rdb);
`rdb' specifies the remote database object.
The return value is the size of the database or 0 if the object does not connect to any database server.

The function `tcrdbstat' is used in order to get the status string of the database of a remote database object.

char *tcrdbstat(TCRDB *rdb);
`rdb' specifies the remote database object.
The return value is the status message of the database or `NULL' if the object does not connect to any database server. The message format is TSV. The first field of each line means the parameter name and the second field means the value.
Because the region of the return value is allocated with the `malloc' call, it should be released with the `free' call when it is no longer in use.

Example Code

The following code is an example to use a remote database.

#include <tcrdb.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

int main(int argc, char **argv){

  TCRDB *rdb;
  int ecode;
  char *value;

  /* create the object */
  rdb = tcrdbnew();

  /* open the database */
  if(!tcrdbopen(rdb, "localhost", 1978)){
    ecode = tcrdbecode(rdb);
    fprintf(stderr, "open error: %s\n", tcrdberrmsg(ecode));
  }

  /* store records */
  if(!tcrdbput2(rdb, "foo", "hop") ||
     !tcrdbput2(rdb, "bar", "step") ||
     !tcrdbput2(rdb, "baz", "jump")){
    ecode = tcrdbecode(rdb);
    fprintf(stderr, "put error: %s\n", tcrdberrmsg(ecode));
  }

  /* retrieve records */
  value = tcrdbget2(rdb, "foo");
  if(value){
    printf("%s\n", value);
    free(value);
  } else {
    ecode = tcrdbecode(rdb);
    fprintf(stderr, "get error: %s\n", tcrdberrmsg(ecode));
  }

  /* close the database */
  if(!tcrdbclose(rdb)){
    ecode = tcrdbecode(rdb);
    fprintf(stderr, "close error: %s\n", tcrdberrmsg(ecode));
  }

  /* delete the object */
  tcrdbdel(rdb);

  return 0;
}

How to Use the Library

The API of C is available by programs conforming to the C89 (ANSI C) standard or the C99 standard. As the header files of Tokyo Tyrant are provided as `tcrdb.h', applications should include it to use the API. As the library is provided as `libtokyotyrant.a' and `libtokyotyrant.so' and they depends `libtokyocabinet.so', `libz.so', `libresolv.so', `libnsl.so', `libpthread.so', `libm.so', and `libc.so', linker options `-ltokyotyrant', `-ltokyocabinet', `-lz', `-lresolv', `-lnsl', `-lpthread', `-lm', and `-lc' are required for build command. A typical build command is the following.

gcc -I/usr/local/include tc_example.c -o tc_example \
  -L/usr/local/lib -ltokyotyrant -ltokyocabinet -lz -lresolv -lnsl -lpthread -lm -lc

You can also use Tokyo Tyrant in programs written in C++. Because each header is wrapped in C linkage (`extern "C"' block), you can simply include them into your C++ programs.


Protocol

The protocol between the server and clients stands on TCP/IP. By default, the service port is bound to every address of the local host and the port number is 1978. Each session of the server and a client is composed of a request and a response. Requests are classified into the following commands. Structure of request and response is determined by the command. The byte order of integer in request and response is big endian.

put: for the function `tcrdbput'
Request: [magic:2][ksiz:4][vsiz:4][kbuf:*][vbuf:*]
Two bytes of the command ID: 0xC8 and 0x10
A 32-bit integer standing for the length of the key
A 32-bit integer standing for the length of the value
Arbitrary data of the key
Arbitrary data of the value
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
putkeep: for the function `tcrdbputkeep'
Request: [magic:2][ksiz:4][vsiz:4][kbuf:*][vbuf:*]
Two bytes of the command ID: 0xC8 and 0x11
A 32-bit integer standing for the length of the key
A 32-bit integer standing for the length of the value
Arbitrary data of the key
Arbitrary data of the value
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
putcat: for the function `tcrdbputcat'
Request: [magic:2][ksiz:4][vsiz:4][kbuf:*][vbuf:*]
Two bytes of the command ID: 0xC8 and 0x12
A 32-bit integer standing for the length of the key
A 32-bit integer standing for the length of the value
Arbitrary data of the key
Arbitrary data of the value
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
putrtt: for the function `tcrdbputrtt'
Request: [magic:2][ksiz:4][vsiz:4][width:4][kbuf:*][vbuf:*]
Two bytes of the command ID: 0xC8 and 0x13
A 32-bit integer standing for the length of the key
A 32-bit integer standing for the length of the value
A 32-bit integer standing for the width
Arbitrary data of the key
Arbitrary data of the value
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
putnr: for the function `tcrdbputnr'
Request: [magic:2][ksiz:4][vsiz:4][kbuf:*][vbuf:*]
Two bytes of the command ID: 0xC8 and 0x18
A 32-bit integer standing for the length of the key
A 32-bit integer standing for the length of the value
Arbitrary data of the key
Arbitrary data of the value
Response: (none)
out: for the function `tcrdbout'
Request: [magic:2][ksiz:4][kbuf:*]
Two bytes of the command ID: 0xC8 and 0x20
A 32-bit integer standing for the length of the key
Arbitrary data of the key
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
get: for the function `tcrdbget'
Request: [magic:2][ksiz:4][kbuf:*]
Two bytes of the command ID: 0xC8 and 0x30
A 32-bit integer standing for the length of the key
Arbitrary data of the key
Response: [code:1]([vsiz:4][vbuf:*])
An 8-bit integer whose value is 0 on success or another on failure
on success: A 32-bit integer standing for the length of the value
on success: Arbitrary data of the value
mget: for the function `tcrdbget3'
Request: [magic:2][rnum:4][{[ksiz:4][kbuf:*]}:*]
Two bytes of the command ID: 0xC8 and 0x31
A 32-bit integer standing for the number of keys
iteration: A 32-bit integer standing for the length of the key
iteration: Arbitrary data of the key
Response: [code:1][rnum:4][{[ksiz:4][vsiz:4][kbuf:*][vbuf:*]}:*]
An 8-bit integer whose value is 0 on success or another on failure
A 32-bit integer standing for the number of records
iteration: A 32-bit integer standing for the length of the key
iteration: A 32-bit integer standing for the length of the value
iteration: Arbitrary data of the key
iteration: Arbitrary data of the value
vsiz: for the function `tcrdbvsiz'
Request: [magic:2][ksiz:4][kbuf:*]
Two bytes of the command ID: 0xC8 and 0x38
A 32-bit integer standing for the length of the key
Arbitrary data of the key
Response: [code:1]([vsiz:4])
An 8-bit integer whose value is 0 on success or another on failure
on success: A 32-bit integer standing for the length of the value
iterinit: for the function `tcrdbiterinit'
Request: [magic:2]
Two bytes of the command ID: 0xC8 and 0x50
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
iternext: for the function `tcrdbiternext'
Request: [magic:2]
Two bytes of the command ID: 0xC8 and 0x51
Response: [code:1]([ksiz:4][kbuf:*])
An 8-bit integer whose value is 0 on success or another on failure
on success: A 32-bit integer standing for the length of the key
on success: Arbitrary data of the key
fwmkeys: for the function `tcrdbfwmkeys'
Request: [magic:2][psiz:4][max:4][pbuf:*]
Two bytes of the command ID: 0xC8 and 0x58
A 32-bit integer standing for the length of the prefix
A 32-bit integer standing for the maximum number of keys to be fetched.
Arbitrary data of the prefix
Response: [code:1][knum:4][{[ksiz:4][kbuf:*]}:*]
An 8-bit integer whose value is 0 on success or another on failure
A 32-bit integer standing for the number of keys
iteration: A 32-bit integer standing for the length of the key
iteration: Arbitrary data of the key
sync: for the function `tcrdbsync'
Request: [magic:2]
Two bytes of the command ID: 0xC8 and 0x70
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
vanish: for the function `tcrdbvanish'
Request: [magic:2]
Two bytes of the command ID: 0xC8 and 0x71
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
copy: for the function `tcrdbcopy'
Request: [magic:2][psiz:4][path:*]
Two bytes of the command ID: 0xC8 and 0x72
A 32-bit integer standing for the length of the path
Arbitrary data of the path
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
restore: for the function `tcrdbrestore'
Request: [magic:2][psiz:4][path:*]
Two bytes of the command ID: 0xC8 and 0x73
A 32-bit integer standing for the length of the path
Arbitrary data of the path
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
setmst: for the function `tcrdbsetmst'
Request: [magic:2][hsiz:4][port:4][host:*]
Two bytes of the command ID: 0xC8 and 0x78
A 32-bit integer standing for the length of the host name
A 32-bit integer standing for the port number
Arbitrary data of the host name
Response: [code:1]
An 8-bit integer whose value is 0 on success or another on failure
rnum: for the function `tcrdbrnum'
Request: [magic:2]
Two bytes of the command ID: 0xC8 and 0x80
Response: [code:1][rnum:8]
An 8-bit integer whose value is always 0
A 64-bit integer standing for the number of records
size: for the function `tcrdbsize'
Request: [magic:2]
Two bytes of the command ID: 0xC8 and 0x81
Response: [code:1][rnum:8]
An 8-bit integer whose value is always 0
A 64-bit integer standing for the size of the database
stat: for the function `tcrdbstat'
Request: [magic:2]
Two bytes of the command ID: 0xC8 and 0x88
Response: [code:1][ssiz:4][sbuf:*]
An 8-bit integer whose value is always 0
A 32-bit integer standing for the length of the status message

To finish the session, the client can shutdown and close the socket at any time. If not closed, the connection can be reused for the next session. If protocol violation or some fatal error occurs the server immediately breaks the session and closes the connection.

As for the memcached compatible protocol, the server implements the following commands; "set", "add", "replace", "get", "delete", "incr", "decr", "stats", "flush_all", "version", and "quit". "noreply" options of update commands are also supported. However, "flags", "exptime", and "cas unique" parameters are ignored. The limitation size of each query is 8192 bytes.

As for the HTTP/1.1 compatible protocol, the server implements the following commands; "GET" (relevant to `tcrdbget'), "HEAD" (relevant to `tcrdbvsiz'), "PUT" (relevant to `tcrdbput'), "POST" (relevant to `tcrdbputkeep'), and "DELETE" (relevant to `tcrdbout'). The URI of each request is treated as the key encoded by the URL encoding. And the entity body is treated as the value. However, headers except for "Connection" and "Content-Length" are ignored. The limitation size of each query is 8192 bytes.


Tutorial

Basic Use

After installation of Tokyo Tyrant, you can start the server immediately by executing the command `ttserver' in the terminal. By default, the server listens to the port 1978 and serves as the accessor of an on-memory database, which is useful to store cache data.

[terminal-1]$ ttserver

To test storing operations, execute the following commands in another terminal. `tcrmgr put' calls the function `tcrdbput'.

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

To test retrieving operations, execute the following commands in another terminal. `tcrmgr get' calls the function `tcrdbget'.

[terminal-2]$ tcrmgr get localhost one
[terminal-2]$ tcrmgr get localhost two
[terminal-2]$ tcrmgr get localhost three

To retrieve multiple records at once, execute the following command. `tcrmgr mget' calls the function `tcrdbget3'.

[terminal-2]$ tcrmgr mget localhost one two three

To terminate the server, input Ctrl-C in the terminal of the server.

Next, let's run the server that handles a hash database, by specifying the file name whose suffix is `.tch'.

[terminal-1]$ ttserver casket.tch

Store some records.

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

Terminate the server by Ctrl-C, and then restart the server.

[terminal-1]$ ttserver casket.tch

Check consistency of stored records.

[terminal-2]$ tcrmgr mget localhost one two three

Terminate the server by Ctrl-C and remove the database, for the successive tutorial.

[terminal-1]$ rm casket.tch

Daemon

To run the server as a daemon process, specify the option `-dmn'. Moreover, the option `-pid' should be specified to record the process ID into a file. Note that the current directory of the daemon process is changed to the root directory. So, the file path parameter should be expressed as absolute path.

[terminal-1]$ ttserver -dmn -pid /tmp/ttserver.pid /tmp/casket.tch

To terminate the daemonized server, check the process ID from the file specified by `-pid' and send the SIGTERM signal to the process.

[terminal-1]$ kill -TERM `cat /tmp/ttserver.pid`

To run the server by the RC script of the operating system, use `ttservctl'. As for most Linux distribution, append the following line to `/etc/rc.local'.

/usr/local/sbin/ttservctl start

By default, the database file and the related files are placed under `/var/ttserver'. Because `ttservctl' is a tiny shell script, copy and edit it for your purpose. Also, it is suitable to install the modified script into `/etc/init.d' and set symbolic links from `/etc/rc3.d/S98ttserver' and `/etc/rc5.d/S98ttserver'.

Backup and Recovery

Let's run the server again to continue this tutorial.

[terminal-1]$ ttserver casket.tch

Store some records.

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

To back up the database file, indicate the destination path to the server by the command `tcrmgr copy'. Note that the backup file is created on the local file system of the server (not on the client side).

[terminal-2]$ tcrmgr copy localhost backup.tch

Terminate the server by Ctrl-C and remove the database.

[terminal-1]$ rm casket.tch

Recover the database from the backup file and restart the server.

[terminal-1]$ cp backup.tch casket.tch
[terminal-1]$ ttserver casket.tch

Check consistency of stored records.

[terminal-2]$ tcrmgr mget localhost one two three

Terminate the server by Ctrl-C and remove the databases, for the successive tutorial.

[terminal-1]$ rm casket.tch backup.tch

Update Log

Let's run the server with update logging enabled. The option `-ulog' specifies the directory to contain the update log files.

[terminal-1]$ mkdir ulog
[terminal-1]$ ttserver -ulog ulog casket.tch

Store some records.

[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third

Terminate the server by Ctrl-C and remove the database.

[terminal-1]$ rm casket.tch

Escape the update log directoty and restart the server.

[terminal-1]$ mv ulog ulog-back
[terminal-1]$ mkdir ulog
[terminal-1]$ ttserver -ulog ulog casket.tch

Restore the database from the escaped update log, by the command `tcrmgr restore' on the client side.

[terminal-2]$ tcrmgr restore localhost ulog-back

Check consistency of stored records.

[terminal-2]$ tcrmgr mget localhost one two three

Terminate the server by Ctrl-C and remove the database, for the successive tutorial.

[terminal-1]$ rm -rf casket.tch ulog ulog-back

Replication

Replication is a mechanism to synchronize two or more database servers for high availability and high integrity. The replication source server is called "master" and each destination server is called "slave". Replication requires the following preconditions.

This section describes how to set up one master (at port 1978) and one slave (at port 1979) replication. First, let's run the master server.

[terminal-1]$ mkdir ulog-1
[terminal-1]$ ttserver -port 1978 -ulog ulog-1 -sid 1 casket-1.tch

Next, let's run the slave server in another terminal.

[terminal-2]$ mkdir ulog-2
[terminal-2]$ ttserver -port 1979 -ulog ulog-2 -sid 2 \
                -mhost localhost -mport 1978 -rts 2.rts casket-2.tch

Store some records into the master.

[terminal-3]$ tcrmgr put -port 1978 localhost one first
[terminal-3]$ tcrmgr put -port 1978 localhost two second
[terminal-3]$ tcrmgr put -port 1978 localhost three third

Check consistency of stored records in the master and the slave.

[terminal-2]$ tcrmgr mget -port 1978 localhost one two three
[terminal-2]$ tcrmgr mget -port 1979 localhost one two three

Let's simulate the case that the master is crashed. Terminate the master by Ctrl-C and remove the database file.

[terminal-1]$ rm casket-1.tch

Terminate the slave by Ctrl-C and restart it as the new master.

[terminal-2]$ ttserver -port 1979 -ulog ulog-2 -sid 2 casket-2.tch

Add the new slave (at port 1980).

[terminal-1]$ mkdir ulog-3
[terminal-1]$ ttserver -port 1980 -ulog ulog-3 -sid 3 \
                -mhost localhost -mport 1979 -rts 3.rts casket-3.tch

Check consistency of stored records in the new master and the new slave.

[terminal-2]$ tcrmgr mget -port 1979 localhost one two three
[terminal-2]$ tcrmgr mget -port 1980 localhost one two three

Terminate the two servers by Ctrl-C and remove the database and related files.

[terminal-1]$ rm -rf casket-1.tch ulog-1 1.rts
[terminal-2]$ rm -rf casket-2.tch ulog-2 2.rts
[terminal-1]$ rm -rf casket-3.tch ulog-3 3.rts

Tokyo Tyrant supports "dual master" replication which realizes higher availability. To do it, run two servers which replicate each other.

Setting Replication on Demand

You can set replication of the running database service without any downtime. First, prepare the following script for backup operation and save it as "ttbackup.sh" with executable permission (0755).

#! /bin/sh
srcpath="$1"
destpath="$1.$2"
rm -f "$destpath"
cp -f "$srcpath" "$destpath"

Next, let's run the master with update log enabled.

[terminal-1]$ mkdir ulog-1
[terminal-1]$ ttserver -port 1978 -ulog ulog-1 -sid 1 casket-1.tch

Store a volume of records into the master.

[terminal-2]$ tcrtest write -port 1978 localhost 10000

Check consistency of stored records.

[terminal-2]$ tcrmgr list -port 1978 -pv localhost

Backup the database.

[terminal-2]$ tcrmgr copy -port 1978 localhost '@./ttbackup.sh'

Confirm that the backup file was saved as "casket-1.tch.xxxxx" ("xxxxx" stands for the time stamp of the backup file). Then, run the slave with the backup file.

[terminal-2]$ ls
[terminal-2]$ cp casket-1.tch.xxxxx casket-2.tch
[terminal-2]$ echo xxxxx > 2.rts
[terminal-2]$ mkdir ulog-2
[terminal-2]$ ttserver -port 1979 -ulog ulog-2 -sid 2 -rts 2.rts casket-2.tch

Note that the above operation did not specify the master server to the slave. For tutorial, let's simulate that some records are stored into the master by users while you are setting replication.

[terminal-3]$ tcrmgr put -port 1978 localhost one first
[terminal-3]$ tcrmgr put -port 1978 localhost two second
[terminal-3]$ tcrmgr put -port 1978 localhost three third

Check the difference between the master and the slave.

[terminal-3]$ tcrmgr inform -port 1978 localhost
[terminal-3]$ tcrmgr inform -port 1979 localhost

Specify the master to the slave so that replication will start and the difference will be resolved.

[terminal-3]$ tcrmgr setmst -port 1979 -mport 1978 localhost localhost

Confirm that the slave knows the master and the difference has been resolved.

[terminal-3]$ tcrmgr inform -port 1979 -st localhost

Terminate the two servers by Ctrl-C and remove the database and related files.

[terminal-1]$ rm -rf casket-1.tch casket-1.tch.* ulog-1 1.rts ttbackup.sh
[terminal-2]$ rm -rf casket-2.tch ulog-2 2.rts

Tuning

If you use a hash database, set the tuning parameter "#bnum=xxx" to improve performance. It specifies the bucket number and should be more than the number of record to be stored.

If you use a B+ tree database, set the tuning parameters "#lcnum=xxx#bnum=yyy" to improve performance. The former specifies the maximum number of leaf nodes to be cached. It should be larger as long as the capacity of RAM on the system allows. The latter specifies the bucket number and should be more than 1/128 of the number of records to be stored.

If huge number of clients access the server, make sure the limit number of file descriptors per a process is cleared. By default on most systems, it is set as 1024. If so, use `ulimit' to clear it.

Using memcached Client

This section describes how to use a memcached client library of Perl (Cache::Memcached) with Tokyo Tyrant. Run the server of Tokyo Tyrant as usual. And, the following script is a typical example.

use Cache::Memcached;

my $memd = Cache::Memcached->new();
$memd->set_servers(['localhost:1978']);

$memd->set('one', 'first');
$memd->set('two', 'second');
$memd->set('three', 'third');

my $val = $memd->get('one');
printf('one: %s\n', $val);

$val = $memd->get_multi('one', 'two', 'three');
printf("one: %s\n", $val->{one});
printf("two: %s\n", $val->{two});
printf("three: %s\n", $val->{three});

$memd->delete('one');

Using HTTP Client

This section describes how to use an HTTP client library of Perl (LWP::UserAgent) with Tokyo Tyrant. Run the server of Tokyo Tyrant as usual. And, the following script is a typical example.

use LWP::UserAgent;

my $ua = LWP::UserAgent->new(keep_alive => 1);
my $baseurl = 'http://localhost:1978/';

my $req;
$req = HTTP::Request->new(PUT => $baseurl . 'one', [], 'first');
$ua->request($req);
$req = HTTP::Request->new(PUT => $baseurl . 'two', [], 'second');
$ua->request($req);
$req = HTTP::Request->new(PUT => $baseurl . 'three', [], 'third');
$ua->request($req);

$req = HTTP::Request->new(GET => $baseurl . 'one');
my $res = $ua->request($req);
if($res->is_success()){
    printf("%s\n", $res->content());
}

$req = HTTP::Request->new(DELETE => $baseurl . 'one');
$ua->request($req);

License

Tokyo Tyrant is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License or any later version.

Tokyo Tyrant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with Tokyo Tyrant (See the file `COPYING'); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

Tokyo Tyrant was written by Mikio Hirabayashi. You can contact the author by e-mail to `mikio@users.sourceforge.net'.