Tokyo Cabinet and Tokyo Tyrant
1. Tokyo Products
2. Tokyo Cabinet (a modern implementation of DBM)
2.1 Tokyo Cabinet 이란?
- Tokyo Cabinet은 hash table, B+ tree, fixed-length array 방식을 지원하는 DBM 스타일의 Embedded library 이다.
- Key-Value 쌍의 레코드를 저장하는 간단한 데이터 파일이다.
- data table이나 data types 개념도 있다.
- 비슷한 키-밸류 형태의 디비 : DBM, NDBM(New DBM), GDBM(GNU DBM), TDB, CDB, Berkeley DB
- SQL개념의 질의문 지원 안하고 API를 이용
- DBMS가 아니다.(library형태이니)
- Tokyo Cabinet is written in the C language
- provided as API of C, Perl, Ruby, Java, and Lua.
- Tokyo Cabinet is a free software licensed under the GNU Lesser General Public License.
2.2 Tokyo Cabinet의 특징
- high performance
- insert: 0.4 sec/1M records - 2,500,000 qps(Queries per second)
- search: 0.33 sec/1M records - 3,000,000 qps
- high concurrency
- multi-thread safe
- read/write locking by records
- high scalability
- hash and B+tree structure = O(1) and O(log N)
- no actual limit size of a database file (to 8 exabytes)
2.3 주요기능
TCHDB: Hash Database
- each key must be unique within a database (key가 unique해야 함)
- impossible to store two or more records with a key overlaps (중복키로 두개 이상 저장 불가)
- These access methods are similar to ones of DBM (or its followers: NDBM and GDBM) library defined in the UNIX standard
- static hashing : O(1) time complexity
TCBDB: B+ Tree Database
- As for database of B+ tree, records whose keys are duplicated can be stored (Key 중복된 레코드 저장 가능)
- Access methods of storing, deleting, and retrieving are provided as with the database of hash table(저장, 삭제, 검색방식은 해시 테이블의 데이터베이스로 제공된다.)
- It is possible to access each record with the cursor in ascending or descending order
- B+ tree : O(log N) time complexity
- custom comparison function : prefix/range matching
- cursor : jump/next/prev
TCFDB: Fixed-length Database
- As for database of fixed-length array, records are stored with unique natural numbers (레코드 저장시 unique natural number가 저장됨)
- It is impossible to store two or more records with a key overlaps (키 중복으로 두 개 이상의 레코드를 저장 불가)
- Moreover, the length of each record is limited by the specified length (또한, 각 레코드의 길이가 특정 길이로 제한)
- Provided operations are the same as ones of hash database.
- array of fixedlength elements : O(1) time complexity
TCTDB: Table Database
- Table database is also provided as a variant of hash database. (해시 데이터베이스를 변형으로 제공)
- Each record is identified by the primary key and has a set of named columns (각 레코드는 기본 키에 의해 식별, 이름 컬럼 세트 구조)
- Although there is no concept of data schema, it is possible to search for records with complex conditions efficiently by using indices of arbitrary columns.
(데이터 스키마의 개념이없지만, 효율적으로 임의의 열 인덱스를 사용하여 복잡한 조건에 레코드를 검색 할 수 있다.)
2.4 Tokyo Cabinet 설치
다운로드
설치
- tokyocabinet-1.4.48.tar.gz 파일을 다운받아서 configure, make, make install만 하면 된다.
- 아래 라이브러리가 필요하다. 없으면 모두 설치 해야 함
- zlib : for loss-less data compression. 1.2.3 or later is suggested.
- bzip2 : for loss-less data compression. 1.0.5 or later is suggested.
wget http://fallabs.com/tokyocabinet/tokyocabinet-1.4.48.tar.gz
tar zxvf tokyocabinet-1.4.48.tar.gz
cd tokyocabinet-1.4.48
./configure --prefix=/cloud/env/tokyocabinet
make
#================================================================
# Ready to install.
#================================================================
make install
#================================================================
# Thanks for using Tokyo Cabinet.
#================================================================
2.5 Tokyo Cabinet Example code
C Example code
*tokyocabinet-1.4.48.tar.gz 압축을 해제하면 example 폴더에 예제 파일이 존재함
include <tcutil.h>
#include <tchdb.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
int main(int argc, char **argv){
TCHDB *hdb;
int ecode;
char *key, *value;
/* create the object */
hdb = tchdbnew();
/* open the database */
if(!tchdbopen(hdb, "casket.tch", HDBOWRITER | HDBOCREAT)){
ecode = tchdbecode(hdb);
fprintf(stderr, "open error: %s\n", tchdberrmsg(ecode));
}
/* store records */
if(!tchdbput2(hdb, "foo", "hop") ||
!tchdbput2(hdb, "bar", "step") ||
!tchdbput2(hdb, "baz", "jump")){
ecode = tchdbecode(hdb);
fprintf(stderr, "put error: %s\n", tchdberrmsg(ecode));
}
/* retrieve records */
value = tchdbget2(hdb, "foo");
if(value){
printf("%s\n", value);
free(value);
} else {
ecode = tchdbecode(hdb);
fprintf(stderr, "get error: %s\n", tchdberrmsg(ecode));
}
/* traverse records */
tchdbiterinit(hdb);
while((key = tchdbiternext2(hdb)) != NULL){
value = tchdbget2(hdb, key);
if(value){
printf("%s:%s\n", key, value);
free(value);
}
free(key);
}
/* close the database */
if(!tchdbclose(hdb)){
ecode = tchdbecode(hdb);
fprintf(stderr, "close error: %s\n", tchdberrmsg(ecode));
}
/* delete the object */
tchdbdel(hdb);
return 0;
}
JAVA Example code
import java.util.Map;
import java.util.HashMap;
import tokyocabinet.TDB;
public class TestTokyoCabinet {
public static void main(String[] args) {
TDB tdb = new TDB();
if(tdb.open("/tmp/tdb.db", TDB.OWRITER | TDB.OCREAT)) {
System.out.println("open successful");
} else {
System.out.println("open fail");
}
Map<String, Object> person = new HashMap<String, Object>(2);
person.put("name", "james");
person.put("age", 25);
if(!tdb.put("james", person)) {
System.out.println("put error:" + tdb.errmsg(tdb.ecode()));
}
Map<String, Object> ret = tdb.get("james");
for (String key : ret.keySet()) {
System.out.println(key + ":" + ret.get(key));
}
tdb.close();
}
}
3. Tokyo Tyrant (network interface of Tokyo Cabinet)
3.1 Tokyo Tyrant 란?
- Tokyo Cabinet을 클라이언트-서버 구조의 데이터베이스처럼 사용할 수 있게 해주는 인터페이스와 서버 프로세스 이다.
- client/server model, multi applications can access one database
- 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
- 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.
(클라이언트 응용 프로그램에 대한 데이터베이스와 ACCESS 라이브러리를 관리하는 서버 프로세스로 구성되어 있습니다.)
3.2 Tokyo Tyrant의 특징
- Linux/*BSD kernel의 epoll/[kqueue|http://en.wikipedia.org/wiki/Kqueue] mechanism과 thread-pool model을 구현하여 high concurrency를 제공한다.
- server와 clients가 TCP/IP(on)에 대한 simple binary protocol로 통신한다.
- memcached와 HTTP를 지원하며 거의 모든 플랫폼과 프로그램 언어를 Tokyo Tyrant에서 사용할 수 있도록 지원한다.
- Linux, FreeBSD, Mac OS X, Solaris에서만 사용가능 하다
- high availability
- hot backup and update log
- asynchronous replication between servers
- various database schema (using the abstract database API of Tokyo Cabinet)
- on-memory hash database API
- the on-memory tree database API
- the hash API
- the B+ tree database API
- the fixed-length database API
- the table database API
- pure script language interfaces
- Perl, Ruby, Java, Python, PHP, Erlang, etc...
3.3 주요기능
Asynchronous Replication
- Master-Slaves 구조와 Dual Master 구조 지원
Thread Pool Model
- hread Pool Model 지원 : 고정 개수의 Thread를 미리 생성하여 Pool을 구성하고 필요 할 때마다 Pool로 부터 할당
3.4 Tokyo Tyrant 설치 ( tokyotyrant-1.1.41.tar.gz )
wget http://fallabs.com/tokyotyrant/tokyotyrant-1.1.41.tar.gz
tar zxvf tokyotyrant-1.1.41.tar.gz
cd tokyotyrant-1.1.41
#tokyocabinet HOME 지정
./configure --prefix=/home/gurubee/cloud/env/tokyotyrant --with-tc=/home/gurubee/cloud/env/tokyocabinet
#================================================================
# Ready to make.
#================================================================
make
#================================================================
# Ready to install.
#================================================================
make install
#================================================================
# Thanks for using Tokyo Tyrant.
#================================================================
Tokyo Tyrant 실행
- ttserver 명령을 실행하여 Tokyo Tyrant 서버를 기동한다.
mkdir /home/gurubee/cloud/data/tc-data
/home/gurubee/cloud/env/tokyotyrant/bin/ttserver
-port 11211 -thnum 8 -dmn
-pid /home/gurubee/cloud/data/tc-data/ttserver.pid
-log /home/gurubee/cloud/data/tc-data/ttserver.log -le
-ulog /home/gurubee/cloud/data/tc-data/ -ulim 128m -sid 1
-rts /home/gurubee/cloud/data/tc-data/ttserver.rts /home/gurubee/cloud/data/tc-data/database.tcb
netstat -anp | grep LISTEN
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 19714/ttserver
- ttserver Option
- -host name : specify the host name or the address of the server. By default, every network address is bound.
- -port num : specify the port number. By default, it is 1978.
- -thnum num : specify the number of worker threads. By default, it is 8.
- -pid path : output the process ID into the file.
- -log path : output log messages into the file.
- -ulog path : specify the update log directory.
3.5 Tokyo Tyrant Example Code
C Example Code
#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();
/* connect to the server */
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 connection */
if(!tcrdbclose(rdb)){
ecode = tcrdbecode(rdb);
fprintf(stderr, "close error: %s\n", tcrdberrmsg(ecode));
}
/* delete the object */
tcrdbdel(rdb);
return 0;
}
JAVA Example Code
import java.io.IOException;
import java.net.InetSocketAddress;
import tokyotyrant.RDB;
import tokyotyrant.transcoder.DoubleTranscoder;
import tokyotyrant.transcoder.IntegerTranscoder;
public class RDBExample {
public static void main(String[] args) throws IOException {
Object key;
Object value;
// create the object
RDB db = new RDB();
// connect to the server
db.open(new InetSocketAddress("localhost", 1978));
// store records
if (!db.put("foo", "hop")
|| !db.put("bar", "step")
|| !db.put("baz", "jump")) {
System.err.println("put error");
}
// retrieve records
value = db.get("foo");
if (value != null) {
System.out.println(value);
} else {
System.err.println("get error");
}
// traverse records
db.iterinit();
while ((key = db.iternext()) != null) {
value = db.get(key);
if (value != null) {
System.out.println(key + ":" + value);
}
}
// add int
db.put("int", 3, new IntegerTranscoder());
int i = db.addint("int", 4);
System.out.println(i);
// add double
db.put("d", 3.0D, new DoubleTranscoder());
double d = db.adddouble("d", 4.0D);
System.out.println(d);
// close the connection
db.close();
}
}
import tokyotyrant.MRDB;
import tokyotyrant.networking.NodeAddress;
import tokyotyrant.transcoder.DoubleTranscoder;
import tokyotyrant.transcoder.IntegerTranscoder;
public class MRDBExample {
public static void main(String[] args) throws Exception {
Object value;
// create the object
MRDB db = new MRDB();
// connect to the servers
db.open(NodeAddress.addresses("tcp://localhost:1978"));
// store records
if (!db.await(db.put("foo", "hop"))
|| !db.await(db.put("bar", "step"))
|| !db.await(db.put("baz", "jump"))) {
System.err.println("put error");
}
// retrieve records
value = db.await(db.get("foo"));
if (value != null) {
System.out.println(value);
} else {
System.err.println("get error");
}
// add int
db.put("int", 3, new IntegerTranscoder());
int i = db.await(db.addint("int", 4));
System.out.println(i);
// add double
db.put("d", 3.0D, new DoubleTranscoder());
double d = db.await(db.adddouble("d", 4.0D));
System.out.println(d);
// close the connections
db.close();
}
}
4. 참고자료