diff options
author | Eitan Adler <eadler@FreeBSD.org> | 2012-01-02 15:41:28 +0000 |
---|---|---|
committer | Eitan Adler <eadler@FreeBSD.org> | 2012-01-02 15:41:28 +0000 |
commit | 4ca7312e0e4f57600720f8e2c8ef343d5b03920a (patch) | |
tree | 26979d4606efbbd4c17c134fbb041aa7ebe768da /databases | |
parent | 2f2516d4df04f9ee2e7e9bbe7214ad2e476e6261 (diff) |
Notes
Diffstat (limited to 'databases')
-rw-r--r-- | databases/Makefile | 1 | ||||
-rw-r--r-- | databases/tarantool/Makefile | 43 | ||||
-rw-r--r-- | databases/tarantool/distinfo | 2 | ||||
-rw-r--r-- | databases/tarantool/files/patch-CMakeLists.txt | 11 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_CMakeLists.txt | 9 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_box_tarantool.cfg | 17 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_lib_sql.g | 57 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_lib_sql.py | 92 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_lib_sql_ast.py | 45 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_lib_tarantool_connection.py | 158 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_lib_tarantool_silverbox_server.py | 266 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_lib_test_suite.py | 210 | ||||
-rw-r--r-- | databases/tarantool/files/patch-test_tarantool | 30 | ||||
-rw-r--r-- | databases/tarantool/files/pkg-message.in | 10 | ||||
-rw-r--r-- | databases/tarantool/files/tarantool.in | 29 | ||||
-rw-r--r-- | databases/tarantool/pkg-descr | 5 | ||||
-rw-r--r-- | databases/tarantool/pkg-plist | 21 |
17 files changed, 1006 insertions, 0 deletions
diff --git a/databases/Makefile b/databases/Makefile index 95b6d8426798..9881c87086c9 100644 --- a/databases/Makefile +++ b/databases/Makefile @@ -803,6 +803,7 @@ SUBDIR += squirrel-sql SUBDIR += sybtcl SUBDIR += tablelog + SUBDIR += tarantool SUBDIR += tcl-Mysql SUBDIR += tdb SUBDIR += tinycdb diff --git a/databases/tarantool/Makefile b/databases/tarantool/Makefile new file mode 100644 index 000000000000..05cc4e32203a --- /dev/null +++ b/databases/tarantool/Makefile @@ -0,0 +1,43 @@ +# New ports collection makefile for: tarantool +# Date created: 2011-11-25 +# Whom: Gvozdikov Veniamin <g.veniamin@googlemail.com> +# +# $FreeBSD$ +# + +PORTNAME= tarantool +PORTVERSION= 1.3.5 +CATEGORIES= databases +MASTER_SITES= http://launchpadlibrarian.net/71705094/ +DISTNAME= ${PORTNAME}-${PORTVERSION}-src + +MAINTAINER= g.veniamin@googlemail.com +COMMENT= Tarantool, is a high performance key/value storage server + +LICENSE= BSD + +ONLY_FOR_ARCHS= i386 + +USE_CMAKE= yes +ARCH= i386 +USE_RC_SUBR= ${PORTNAME} +SUB_FILES= pkg-message + +.include <bsd.port.pre.mk> + +post-patch: + @${REINPLACE_CMD} -e 's|%%DOCSDIR%%|${DOCSDIR}|g' \ + ${WRKSRC}/CMakeLists.txt + @${REINPLACE_CMD} -e 's|%%ETCDIR%%|${ETCDIR}|g' \ + ${WRKSRC}/test/CMakeLists.txt + @${RM} ${WRKSRC}/test/lib/server.py \ + ${WRKSRC}/test/lib/silverbox.py \ + ${WRKSRC}/test/lib/tarantool_admin.py \ + ${WRKSRC}/test/lib/tarantool_feeder_server.py \ + ${WRKSRC}/test/lib/tarantool_server.py \ + ${WRKSRC}/test/lib/*.orig + +post-install: + @${CAT} ${PKGMESSAGE} + +.include <bsd.port.post.mk> diff --git a/databases/tarantool/distinfo b/databases/tarantool/distinfo new file mode 100644 index 000000000000..1eaf253b1299 --- /dev/null +++ b/databases/tarantool/distinfo @@ -0,0 +1,2 @@ +SHA256 (tarantool-1.3.5-src.tar.gz) = c78eb302eabac7b6ae04a8eadf8b2819e992d2913cdafe1a86222148982351ec +SIZE (tarantool-1.3.5-src.tar.gz) = 829327 diff --git a/databases/tarantool/files/patch-CMakeLists.txt b/databases/tarantool/files/patch-CMakeLists.txt new file mode 100644 index 000000000000..dfce258c4ca2 --- /dev/null +++ b/databases/tarantool/files/patch-CMakeLists.txt @@ -0,0 +1,11 @@ +--- CMakeLists.txt.orig 2011-11-25 15:33:08.997444924 +0000 ++++ CMakeLists.txt 2011-11-25 15:33:30.428593855 +0000 +@@ -197,7 +197,7 @@ + add_subdirectory(test) + + install (FILES README LICENSE doc/silverbox-protocol.txt +- DESTINATION doc) ++ DESTINATION %%DOCSDIR%%) + + include (cmake/tarantool_cpack.cmake) + # diff --git a/databases/tarantool/files/patch-test_CMakeLists.txt b/databases/tarantool/files/patch-test_CMakeLists.txt new file mode 100644 index 000000000000..63afe8fbb2d6 --- /dev/null +++ b/databases/tarantool/files/patch-test_CMakeLists.txt @@ -0,0 +1,9 @@ +--- test/CMakeLists.txt.orig 2011-12-11 16:16:40.594230551 +0000 ++++ test/CMakeLists.txt 2011-12-11 16:19:44.915010706 +0000 +@@ -9,5 +9,4 @@ + + install (PROGRAMS tarantool DESTINATION bin) + install (DIRECTORY lib DESTINATION bin) +-install (FILES box/tarantool.cfg box/00000000000000000001.snap +- DESTINATION bin) ++install (FILES box/tarantool.cfg DESTINATION %%ETCDIR%%) diff --git a/databases/tarantool/files/patch-test_box_tarantool.cfg b/databases/tarantool/files/patch-test_box_tarantool.cfg new file mode 100644 index 000000000000..35329ad4bd32 --- /dev/null +++ b/databases/tarantool/files/patch-test_box_tarantool.cfg @@ -0,0 +1,17 @@ +--- test/box/tarantool.cfg.orig 2011-12-13 01:02:02.069760259 +0000 ++++ test/box/tarantool.cfg 2011-12-13 01:03:52.550055101 +0000 +@@ -1,11 +1,11 @@ + slab_alloc_arena = 0.1 + +-pid_file = "box.pid" +- ++pid_file = "/var/run/tarantool.pid" ++work_dir = "/var/db/tarantool" + + # Use -a not -a to work correctly on FreeBSD + # +-logger="tee -a tarantool.log" ++logger="cat >> /var/log/tarantool.log" + + primary_port = 33013 + secondary_port = 33014 diff --git a/databases/tarantool/files/patch-test_lib_sql.g b/databases/tarantool/files/patch-test_lib_sql.g new file mode 100644 index 000000000000..cbb53b447328 --- /dev/null +++ b/databases/tarantool/files/patch-test_lib_sql.g @@ -0,0 +1,57 @@ +--- test/lib/sql.g.orig 2011-05-14 12:16:32.000000000 +0000 ++++ test/lib/sql.g 2011-12-13 00:41:37.729004939 +0000 +@@ -5,10 +5,6 @@ + + %% + +-# The grammar below solely covers the functionality provided by +-# Tarantool binary protocol, from which follow all the +-# limitations. For reference please see doc/box-protocol.txt. +- + parser sql: + + ignore: '\\s+' +@@ -25,8 +21,6 @@ + token WHERE: 'where' + token VALUES: 'values' + token SET: 'set' +- token OR: 'or' +- token LIMIT: 'limit' + token END: '\\s*$' + + rule sql: (insert {{ stmt = insert }} | +@@ -37,27 +31,19 @@ + + rule insert: INSERT [INTO] ident VALUES value_list + {{ return sql_ast.StatementInsert(ident, value_list) }} +- rule update: UPDATE ident SET update_list opt_simple_where +- {{ return sql_ast.StatementUpdate(ident, update_list, opt_simple_where) }} +- rule delete: DELETE FROM ident opt_simple_where +- {{ return sql_ast.StatementDelete(ident, opt_simple_where) }} +- rule select: SELECT '\*' FROM ident opt_where opt_limit +- {{ return sql_ast.StatementSelect(ident, opt_where, opt_limit) }} ++ rule update: UPDATE ident SET update_list opt_where ++ {{ return sql_ast.StatementUpdate(ident, update_list, opt_where) }} ++ rule delete: DELETE FROM ident opt_where ++ {{ return sql_ast.StatementDelete(ident, opt_where) }} ++ rule select: SELECT '\*' FROM ident opt_where ++ {{ return sql_ast.StatementSelect(ident, opt_where) }} + rule ping: PING + {{ return sql_ast.StatementPing() }} + rule predicate: ident '=' constant + {{ return (ident, constant) }} +- rule opt_simple_where: {{ return None }} ++ rule opt_where: {{ return None }} + | WHERE predicate + {{ return predicate }} +- rule opt_where: {{ return None }} +- | WHERE disjunction +- {{ return disjunction }} +- rule disjunction: predicate {{ disjunction = [predicate] }} +- [(OR predicate {{ disjunction.append(predicate) }})+] +- {{ return disjunction }} +- rule opt_limit: {{ return 0xffffffff }} +- | LIMIT NUM {{ return int(NUM) }} + rule value_list: '\(' expr {{ value_list = [expr] }} + [("," expr {{ value_list.append(expr) }} )+] + '\)' {{ return value_list }} diff --git a/databases/tarantool/files/patch-test_lib_sql.py b/databases/tarantool/files/patch-test_lib_sql.py new file mode 100644 index 000000000000..30b56f1df11e --- /dev/null +++ b/databases/tarantool/files/patch-test_lib_sql.py @@ -0,0 +1,92 @@ +--- test/lib/sql.py.orig 2011-05-14 12:16:32.000000000 +0000 ++++ test/lib/sql.py 2011-12-13 00:23:04.673107891 +0000 +@@ -30,8 +30,6 @@ + ('WHERE', re.compile('where')), + ('VALUES', re.compile('values')), + ('SET', re.compile('set')), +- ('OR', re.compile('or')), +- ('LIMIT', re.compile('limit')), + ('END', re.compile('\\s*$')), + ] + def __init__(self, str,*args,**kw): +@@ -76,16 +74,16 @@ + ident = self.ident(_context) + SET = self._scan('SET', context=_context) + update_list = self.update_list(_context) +- opt_simple_where = self.opt_simple_where(_context) +- return sql_ast.StatementUpdate(ident, update_list, opt_simple_where) ++ opt_where = self.opt_where(_context) ++ return sql_ast.StatementUpdate(ident, update_list, opt_where) + + def delete(self, _parent=None): + _context = self.Context(_parent, self._scanner, 'delete', []) + DELETE = self._scan('DELETE', context=_context) + FROM = self._scan('FROM', context=_context) + ident = self.ident(_context) +- opt_simple_where = self.opt_simple_where(_context) +- return sql_ast.StatementDelete(ident, opt_simple_where) ++ opt_where = self.opt_where(_context) ++ return sql_ast.StatementDelete(ident, opt_where) + + def select(self, _parent=None): + _context = self.Context(_parent, self._scanner, 'select', []) +@@ -94,8 +92,7 @@ + FROM = self._scan('FROM', context=_context) + ident = self.ident(_context) + opt_where = self.opt_where(_context) +- opt_limit = self.opt_limit(_context) +- return sql_ast.StatementSelect(ident, opt_where, opt_limit) ++ return sql_ast.StatementSelect(ident, opt_where) + + def ping(self, _parent=None): + _context = self.Context(_parent, self._scanner, 'ping', []) +@@ -109,8 +106,8 @@ + constant = self.constant(_context) + return (ident, constant) + +- def opt_simple_where(self, _parent=None): +- _context = self.Context(_parent, self._scanner, 'opt_simple_where', []) ++ def opt_where(self, _parent=None): ++ _context = self.Context(_parent, self._scanner, 'opt_where', []) + _token = self._peek('WHERE', 'END', context=_context) + if _token == 'END': + return None +@@ -119,38 +116,6 @@ + predicate = self.predicate(_context) + return predicate + +- def opt_where(self, _parent=None): +- _context = self.Context(_parent, self._scanner, 'opt_where', []) +- _token = self._peek('WHERE', 'LIMIT', 'END', context=_context) +- if _token != 'WHERE': +- return None +- else: # == 'WHERE' +- WHERE = self._scan('WHERE', context=_context) +- disjunction = self.disjunction(_context) +- return disjunction +- +- def disjunction(self, _parent=None): +- _context = self.Context(_parent, self._scanner, 'disjunction', []) +- predicate = self.predicate(_context) +- disjunction = [predicate] +- if self._peek('OR', 'LIMIT', 'END', context=_context) == 'OR': +- while 1: +- OR = self._scan('OR', context=_context) +- predicate = self.predicate(_context) +- disjunction.append(predicate) +- if self._peek('OR', 'LIMIT', 'END', context=_context) != 'OR': break +- return disjunction +- +- def opt_limit(self, _parent=None): +- _context = self.Context(_parent, self._scanner, 'opt_limit', []) +- _token = self._peek('LIMIT', 'END', context=_context) +- if _token == 'END': +- return 0xffffffff +- else: # == 'LIMIT' +- LIMIT = self._scan('LIMIT', context=_context) +- NUM = self._scan('NUM', context=_context) +- return int(NUM) +- + def value_list(self, _parent=None): + _context = self.Context(_parent, self._scanner, 'value_list', []) + self._scan("'\\('", context=_context) diff --git a/databases/tarantool/files/patch-test_lib_sql_ast.py b/databases/tarantool/files/patch-test_lib_sql_ast.py new file mode 100644 index 000000000000..e7b5bec34c89 --- /dev/null +++ b/databases/tarantool/files/patch-test_lib_sql_ast.py @@ -0,0 +1,45 @@ +--- test/lib/sql_ast.py.orig 2011-05-14 12:16:32.000000000 +0000 ++++ test/lib/sql_ast.py 2011-12-13 00:23:04.673107891 +0000 +@@ -242,22 +242,16 @@ + class StatementSelect(StatementPing): + reqeust_type = SELECT_REQUEST_TYPE + +- def __init__(self, table_name, where, limit): ++ def __init__(self, table_name, where): + self.namespace_no = table_name +- self.index_no = None +- self.key_list = [] +- if not where: +- self.index_no = 0 +- self.key_list = ["",] ++ if where: ++ (self.index_no, key) = where ++ self.key = [key] + else: +- for (index_no, key) in where: +- self.key_list.append(key) +- if self.index_no == None: +- self.index_no = index_no +- elif self.index_no != index_no: +- raise RuntimeError("All key values in a disjunction must refer to the same index") ++ self.index_no = 0 ++ self.key = [""] + self.offset = 0 +- self.limit = limit ++ self.limit = 0xffffffff + + def pack(self): + buf = ctypes.create_string_buffer(PACKET_BUF_LEN) +@@ -266,10 +260,8 @@ + self.index_no, + self.offset, + self.limit, +- len(self.key_list)) +- offset = SELECT_REQUEST_FIXED_LEN +- for key in self.key_list: +- (buf, offset) = pack_tuple([key], buf, offset) ++ 1) ++ (buf, offset) = pack_tuple(self.key, buf, SELECT_REQUEST_FIXED_LEN) + + return buf[:offset] + diff --git a/databases/tarantool/files/patch-test_lib_tarantool_connection.py b/databases/tarantool/files/patch-test_lib_tarantool_connection.py new file mode 100644 index 000000000000..0df906fbde11 --- /dev/null +++ b/databases/tarantool/files/patch-test_lib_tarantool_connection.py @@ -0,0 +1,158 @@ +--- test/lib/tarantool_connection.py.orig 1970-01-01 00:00:00.000000000 +0000 ++++ test/lib/tarantool_connection.py 2011-12-13 00:23:04.673107891 +0000 +@@ -0,0 +1,155 @@ ++__author__ = "Konstantin Osipov <kostja.osipov@gmail.com>" ++ ++# Redistribution and use in source and binary forms, with or without ++# modification, are permitted provided that the following conditions ++# are met: ++# 1. Redistributions of source code must retain the above copyright ++# notice, this list of conditions and the following disclaimer. ++# 2. Redistributions in binary form must reproduce the above copyright ++# notice, this list of conditions and the following disclaimer in the ++# documentation and/or other materials provided with the distribution. ++# ++# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE ++# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++# SUCH DAMAGE. ++ ++import socket ++import sys ++import string ++import cStringIO ++import yaml ++import re ++import sql ++import struct ++import errno ++ ++is_admin_re = re.compile("^\s*(show|save|exec|exit|reload|help)", re.I) ++ ++class AdminConnection: ++ def __init__(self, host, port): ++ self.host = host ++ self.port = port ++ self.is_connected = False ++ self.stream = cStringIO.StringIO() ++ ++ def connect(self): ++ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++ self.socket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) ++ self.socket.connect((self.host, self.port)) ++ self.is_connected = True ++ ++ def disconnect(self): ++ if self.is_connected: ++ self.socket.close() ++ self.is_connected = False ++ ++ def reconnect(self): ++ self.disconnect() ++ self.connect() ++ ++ def opt_reconnect(self): ++ """ On a socket which was disconnected, recv of 0 bytes immediately ++ returns with no data. On a socket which is alive, it returns EAGAIN. ++ Make use of this property and detect whether or not the socket is ++ dead. Reconnect a dead socket, do nothing if the socket is good.""" ++ try: ++ if self.socket.recv(0, socket.MSG_DONTWAIT) == '': ++ self.reconnect() ++ except socket.error as e: ++ if e.errno == errno.EAGAIN: ++ pass ++ else: ++ self.reconnect() ++ ++ def execute(self, command): ++ self.opt_reconnect() ++ return self.execute_no_reconnect(command) ++ ++ def execute_no_reconnect(self, command): ++ self.socket.sendall(command) ++ ++ bufsiz = 4096 ++ res = "" ++ ++ while True: ++ buf = self.socket.recv(bufsiz) ++ if not buf: ++ break ++ res = res + buf; ++ if (res.rfind("\r\n...\r\n") >= 0): ++ break ++ ++ # validate yaml by parsing it ++ yaml.load(res) ++ ++ return res ++ ++ def write(self, fragment): ++ """This is to support print >> admin, "command" syntax. ++ For every print statement, write is invoked twice: one to ++ write the command itself, and another to write \n. We should ++ accumulate all writes until we receive \n. When we receive it, ++ we execute the command, and rewind the stream.""" ++ ++ newline_pos = fragment.rfind("\n") ++ while newline_pos >= 0: ++ self.stream.write(fragment[:newline_pos+1]) ++ statement = self.stream.getvalue() ++ sys.stdout.write(statement) ++ sys.stdout.write(self.execute(statement)) ++ fragment = fragment[newline_pos+1:] ++ newline_pos = fragment.rfind("\n") ++ self.stream.seek(0) ++ self.stream.truncate() ++ ++ self.stream.write(fragment) ++ ++ def __enter__(self): ++ self.connect() ++ return self ++ ++ def __exit__(self, type, value, tb): ++ self.disconnect() ++ ++class DataConnection(AdminConnection): ++ ++ def recvall(self, length): ++ res = "" ++ while len(res) < length: ++ buf = self.socket.recv(length - len(res)) ++ res = res + buf ++ return res ++ ++ def execute_no_reconnect(self, command): ++ statement = sql.parse("sql", command) ++ if statement == None: ++ return "You have an error in your SQL syntax\n" ++ ++ payload = statement.pack() ++ header = struct.pack("<lll", statement.reqeust_type, len(payload), 0) ++ ++ self.socket.sendall(header) ++ if len(payload): ++ self.socket.sendall(payload) ++ ++ IPROTO_HEADER_SIZE = 12 ++ ++ header = self.recvall(IPROTO_HEADER_SIZE) ++ ++ response_len = struct.unpack("<lll", header)[1] ++ ++ if response_len: ++ response = self.recvall(response_len) ++ else: ++ response = None ++ ++ return statement.unpack(response) + "\n" ++ diff --git a/databases/tarantool/files/patch-test_lib_tarantool_silverbox_server.py b/databases/tarantool/files/patch-test_lib_tarantool_silverbox_server.py new file mode 100644 index 000000000000..aa466bacc604 --- /dev/null +++ b/databases/tarantool/files/patch-test_lib_tarantool_silverbox_server.py @@ -0,0 +1,266 @@ +--- test/lib/tarantool_silverbox_server.py.orig 2011-05-14 12:16:32.000000000 +0000 ++++ test/lib/tarantool_silverbox_server.py 2011-12-13 00:23:04.673107891 +0000 +@@ -1,35 +1,234 @@ ++import os ++import stat + import shutil + import subprocess +-import yaml +-import ConfigParser +-from tarantool_server import TarantoolServer, TarantoolConfigFile +-from tarantool_admin import TarantoolAdmin +-from silverbox import Silverbox +- +-class TarantoolSilverboxServer(TarantoolServer): +- def __new__(cls, core="tarantool", module="silverbox"): +- return TarantoolServer.__new__(cls) +- +- def __init__(self, core="tarantool", module="silverbox"): +- TarantoolServer.__init__(self, core, module) +- +- def configure(self, config): +- TarantoolServer.configure(self, config) +- with open(self.config) as fp: +- dummy_section_name = "tarantool" +- config = ConfigParser.ConfigParser() +- config.readfp(TarantoolConfigFile(fp, dummy_section_name)) +- self.primary_port = int(config.get(dummy_section_name, "primary_port")) +- self.admin_port = int(config.get(dummy_section_name, "admin_port")) +- self.port = self.admin_port +- self.admin = TarantoolAdmin("localhost", self.admin_port) +- self.sql = Silverbox("localhost", self.primary_port) +- +- def init(self): +-# init storage +- subprocess.check_call([self.binary, "--init_storage"], +- cwd = self.vardir, ++import pexpect ++import sys ++import signal ++import time ++import socket ++import daemon ++import glob ++ ++def wait_until_connected(host, port): ++ """Wait until the server is started and accepting connections""" ++ is_connected = False ++ while not is_connected: ++ try: ++ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++ sock.connect((host, port)) ++ is_connected = True ++ sock.close() ++ except socket.error as e: ++ time.sleep(0.001) ++ ++ ++def prepare_gdb(args): ++ """Prepare server startup arguments to run under gdb.""" ++ if "TERM" in os.environ: ++ term = os.environ["TERM"] ++ else: ++ term = "xterm" ++ ++ if term not in ["xterm", "rxvt", "urxvt", "gnome-terminal", "konsole"]: ++ raise RuntimeError("--gdb: unsupported terminal {0}".format(term)) ++ ++ args = [ term, "-e ", "gdb", "-ex", "break main", "-ex", "run"] + args ++ return args ++ ++ ++def prepare_valgrind(args, valgrind_opts): ++ "Prepare server startup arguments to run under valgrind." ++ args = ([ "valgrind", "--log-file=valgrind.log", "--quiet" ] + ++ valgrind_opts.split(" ") + args) ++ return args ++ ++ ++def check_tmpfs_exists(): ++ return os.uname()[0] in 'Linux' and os.path.isdir("/dev/shm") ++ ++def create_tmpfs_vardir(vardir): ++ os.mkdir(os.path.join("/dev/shm", vardir)) ++ os.symlink(os.path.join("/dev/shm", vardir), vardir) ++ ++class TarantoolSilverboxServer: ++ """Server represents a single server instance. Normally, the ++ program operates with only one server, but in future we may add ++ replication slaves. The server is started once at the beginning ++ of each suite, and stopped at the end.""" ++ ++ def __init__(self, args, suite_ini): ++ """Set server options: path to configuration file, pid file, exe, etc.""" ++ self.args = args ++ self.suite_ini = suite_ini ++ self.path_to_pidfile = os.path.join(args.vardir, suite_ini["pidfile"]) ++ self.path_to_exe = None ++ self.abspath_to_exe = None ++ self.is_started = False ++ ++ def install(self, silent = False): ++ """Start server instance: check if the old one exists, kill it ++ if necessary, create necessary directories and files, start ++ the server. The server working directory is taken from 'vardir', ++ specified in the prgoram options. ++ Currently this is implemented for tarantool_silverbox only.""" ++ ++ vardir = self.args.vardir ++ ++ if not silent: ++ print "Installing the server..." ++ ++ if self.path_to_exe == None: ++ self.path_to_exe = self.find_exe() ++ self.abspath_to_exe = os.path.abspath(self.path_to_exe) ++ ++ if not silent: ++ print " Found executable at " + self.path_to_exe + "." ++ ++ if not silent: ++ print " Creating and populating working directory in " +\ ++ vardir + "..." ++ ++ if os.access(vardir, os.F_OK): ++ if not silent: ++ print " Found old vardir, deleting..." ++ self.kill_old_server() ++ for filename in (glob.glob(os.path.join(vardir, "*.snap")) + ++ glob.glob(os.path.join(vardir, "*.inprogress")) + ++ glob.glob(os.path.join(vardir, "*.xlog")) + ++ glob.glob(os.path.join(vardir, "*.cfg")) + ++ glob.glob(os.path.join(vardir, "*.log")) + ++ glob.glob(os.path.join(vardir, "*.core.*")) + ++ glob.glob(os.path.join(vardir, "core"))): ++ os.remove(filename) ++ else: ++ if (self.args.mem == True and check_tmpfs_exists() and ++ os.path.basename(vardir) == vardir): ++ create_tmpfs_vardir(vardir) ++ else: ++ os.mkdir(vardir) ++ ++ shutil.copy(self.suite_ini["config"], self.args.vardir) ++ ++ subprocess.check_call([self.abspath_to_exe, "--init_storage"], ++ cwd = self.args.vardir, + # catch stdout/stderr to not clutter output + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + ++ p = subprocess.Popen([self.abspath_to_exe, "--version"], ++ cwd = self.args.vardir, ++ stdout = subprocess.PIPE) ++ version = p.stdout.read().rstrip() ++ p.wait() ++ ++ if not silent: ++ print "Starting {0} {1}.".format(os.path.basename(self.abspath_to_exe), ++ version) ++ ++ def start(self, silent = False): ++ ++ if self.is_started: ++ if not silent: ++ print "The server is already started." ++ return ++ ++ if not silent: ++ print "Starting the server..." ++ ++ args = [self.abspath_to_exe] ++ ++ if (self.args.start_and_exit and ++ not self.args.valgrind and not self.args.gdb): ++ args.append("--daemonize") ++ if self.args.gdb: ++ args = prepare_gdb(args) ++ elif self.args.valgrind: ++ args = prepare_valgrind(args, self.args.valgrind_opts) ++ ++ if self.args.start_and_exit and self.args.valgrind: ++ pid = os.fork() ++ if pid > 0: ++ os.wait() ++ else: ++ with daemon.DaemonContext(working_directory = self.args.vardir): ++ os.execvp(args[0], args) ++ else: ++ self.server = pexpect.spawn(args[0], args[1:], cwd = self.args.vardir) ++ if self.args.start_and_exit: ++ self.server.wait() ++ ++# wait until the server is connectedk ++ if self.args.gdb and self.args.start_and_exit: ++ time.sleep(1) ++ elif not self.args.start_and_exit and not self.args.gdb: ++ self.server.expect_exact("entering event loop") ++ else: ++ wait_until_connected(self.suite_ini["host"], self.suite_ini["port"]) ++ ++# Set is_started flag, to nicely support cleanup during an exception. ++ self.is_started = True ++ ++ ++ def stop(self, silent = False): ++ """Stop server instance. Do nothing if the server is not started, ++ to properly shut down the server in case of an exception during ++ start up.""" ++ if self.is_started: ++ if not silent: ++ print "Stopping the server..." ++ if self.args.gdb: ++ self.kill_old_server(True) ++ self.server.terminate() ++ self.server.expect(pexpect.EOF) ++ self.is_started = False ++ elif not silent: ++ print "The server is not started." ++ ++ def restart(self): ++ self.stop(True) ++ self.start(True) ++ ++ def test_option(self, option_list_str): ++ args = [self.abspath_to_exe] + option_list_str.split() ++ print " ".join([os.path.basename(self.abspath_to_exe)] + args[1:]) ++ output = subprocess.Popen(args, ++ cwd = self.args.vardir, ++ stdout = subprocess.PIPE, ++ stderr = subprocess.STDOUT).stdout.read() ++ print output ++ ++ ++ def find_exe(self): ++ """Locate server executable in the bindir. We just take ++ the first thing looking like an exe in there.""" ++ ++ print " Looking for server binary in {0}...".format(self.args.bindir) ++ if (os.access(self.args.bindir, os.F_OK) == False or ++ stat.S_ISDIR(os.stat(self.args.bindir).st_mode) == False): ++ raise RuntimeError("Directory " + self.args.bindir + " doesn't exist") ++ ++ for f in os.listdir(self.args.bindir): ++ f = os.path.join(self.args.bindir, f) ++ st_mode = os.stat(f).st_mode ++ if stat.S_ISREG(st_mode) and st_mode & stat.S_IXUSR: ++ return f ++ ++ raise RuntimeError("Can't find server executable in " + self.args.bindir) ++ ++ def kill_old_server(self, silent = False): ++ """Kill old server instance if it exists.""" ++ if os.access(self.path_to_pidfile, os.F_OK) == False: ++ return # Nothing to do ++ pid = 0 ++ with open(self.path_to_pidfile) as f: ++ pid = int(f.read()) ++ if not silent: ++ print " Found old server, pid {0}, killing...".format(pid) ++ try: ++ os.kill(pid, signal.SIGTERM) ++ while os.kill(pid, 0) != -1: ++ time.sleep(0.001) ++ except OSError: ++ pass ++ diff --git a/databases/tarantool/files/patch-test_lib_test_suite.py b/databases/tarantool/files/patch-test_lib_test_suite.py new file mode 100644 index 000000000000..f406b086507d --- /dev/null +++ b/databases/tarantool/files/patch-test_lib_test_suite.py @@ -0,0 +1,210 @@ +--- test/lib/test_suite.py.orig 2011-05-14 12:16:32.000000000 +0000 ++++ test/lib/test_suite.py 2011-12-13 00:23:04.673107891 +0000 +@@ -10,13 +10,21 @@ + import filecmp + import shlex + import time +-from server import Server ++from tarantool_silverbox_server import TarantoolSilverboxServer ++from tarantool_connection import AdminConnection, DataConnection + import tarantool_preprocessor + import re + import cStringIO + import string + import traceback + ++class TestRunException(RuntimeError): ++ """A common exception to use across the program.""" ++ def __init__(self, message): ++ self.message = message ++ def __str__(self): ++ return self.message ++ + class FilteredStream: + """Helper class to filter .result file output""" + def __init__(self, filename): +@@ -66,12 +74,12 @@ + """Initialize test properties: path to test file, path to + temporary result file, path to the client program, test status.""" + self.name = name +- self.args = args +- self.suite_ini = suite_ini + self.result = name.replace(".test", ".result") +- self.tmp_result = os.path.join(self.args.vardir, ++ self.tmp_result = os.path.join(suite_ini["vardir"], + os.path.basename(self.result)) + self.reject = name.replace(".test", ".reject") ++ self.args = args ++ self.suite_ini = suite_ini + self.is_executed = False + self.is_executed_ok = None + self.is_equal_result = None +@@ -81,7 +89,7 @@ + """Return true if this test was run successfully.""" + return self.is_executed and self.is_executed_ok and self.is_equal_result + +- def run(self, server): ++ def run(self): + """Execute the test assuming it's a python program. + If the test aborts, print its output to stdout, and raise + an exception. Else, comprare result and reject files. +@@ -91,10 +99,18 @@ + + diagnostics = "unknown" + save_stdout = sys.stdout ++ admin = AdminConnection(self.suite_ini["host"], ++ self.suite_ini["admin_port"]) ++ sql = DataConnection(self.suite_ini["host"], ++ self.suite_ini["port"]) ++ server = self.suite_ini["server"] + try: ++ admin.connect() ++ sql.connect() + sys.stdout = FilteredStream(self.tmp_result) +- stdout_fileno = sys.stdout.stream.fileno() +- execfile(self.name, dict(locals(), **server.__dict__)) ++ server = self.suite_ini["server"] ++ vardir = self.suite_ini["vardir"] ++ execfile(self.name, globals(), locals()) + self.is_executed_ok = True + except Exception as e: + traceback.print_exc(e) +@@ -103,6 +119,8 @@ + if sys.stdout and sys.stdout != save_stdout: + sys.stdout.close() + sys.stdout = save_stdout; ++ admin.disconnect() ++ sql.disconnect() + + self.is_executed = True + +@@ -111,7 +129,7 @@ + + if self.args.valgrind: + self.is_valgrind_clean = \ +- check_valgrind_log(server.valgrind_log) == False ++ check_valgrind_log(self.suite_ini["valgrind_log"]) == False + + if self.is_executed_ok and self.is_equal_result and self.is_valgrind_clean: + print "[ pass ]" +@@ -133,12 +151,12 @@ + where = ": wrong test output" + elif not self.is_valgrind_clean: + os.remove(self.reject) +- self.print_diagnostics(server.valgrind_log, ++ self.print_diagnostics(self.suite_ini["valgrind_log"], + "Test failed! Last 10 lines of valgrind.log:") + where = ": there were warnings in valgrind.log" + +- if not self.args.is_force: +- raise RuntimeError("Failed to run test " + self.name + where) ++ if not self.suite_ini["is_force"]: ++ raise TestRunException("Failed to run test " + self.name + where) + + + def print_diagnostics(self, logfile, message): +@@ -167,6 +185,20 @@ + for line in diff: + sys.stdout.write(line) + ++class TarantoolConfigFile: ++ """ConfigParser can't read files without sections, work it around""" ++ def __init__(self, fp, section_name): ++ self.fp = fp ++ self.section_name = "[" + section_name + "]" ++ def readline(self): ++ if self.section_name: ++ section_name = self.section_name ++ self.section_name = None ++ return section_name ++ # tarantool.cfg puts string values in quote ++ return self.fp.readline().replace("\"", '') ++ ++ + class TestSuite: + """Each test suite contains a number of related tests files, + located in the same directory on disk. Each test file has +@@ -186,13 +218,15 @@ + self.args = args + self.tests = [] + self.ini = {} +- +- self.ini["core"] = "tarantool" +- self.ini["module"] = "silverbox" ++ self.ini["suite_path"] = suite_path ++ self.ini["host"] = "localhost" ++ self.ini["is_force"] = self.args.is_force ++ self.ini["vardir"] = args.vardir ++ self.ini["valgrind_log"] = os.path.join(args.vardir, "valgrind.log") + + if os.access(suite_path, os.F_OK) == False: +- raise RuntimeError("Suite \"" + suite_path +\ +- "\" doesn't exist") ++ raise TestRunException("Suite \"" + suite_path +\ ++ "\" doesn't exist") + + # read the suite config + config = ConfigParser.ConfigParser() +@@ -203,6 +237,16 @@ + self.ini["disabled"] = dict.fromkeys(self.ini["disabled"].split(" ")) + else: + self.ini["disabled"] = dict() ++# import the necessary module for test suite client ++ ++# now read the server config, we need some properties from it ++ ++ with open(self.ini["config"]) as fp: ++ dummy_section_name = "tarantool_silverbox" ++ config.readfp(TarantoolConfigFile(fp, dummy_section_name)) ++ self.ini["pidfile"] = config.get(dummy_section_name, "pid_file") ++ self.ini["admin_port"] = int(config.get(dummy_section_name, "admin_port")) ++ self.ini["port"] = int(config.get(dummy_section_name, "primary_port")) + + print "Collecting tests in \"" + suite_path + "\": " +\ + self.ini["description"] + "." +@@ -216,17 +260,9 @@ + def run_all(self): + """For each file in the test suite, run client program + assuming each file represents an individual test.""" +- try: +- server = Server(self.ini["core"], self.ini["module"]) +- except Exception as e: +- print e +- raise RuntimeError("Unknown server: core = {0}, module = {1}".format( +- self.ini["core"], self.ini["module"])) +- server.deploy(self.ini["config"], +- server.find_exe(self.args.builddir, silent=False), +- self.args.vardir, +- self.args.mem, self.args.start_and_exit, self.args.gdb, self.args.valgrind, +- silent=False) ++ server = TarantoolSilverboxServer(self.args, self.ini) ++ server.install() ++ server.start() + if self.args.start_and_exit: + print " Start and exit requested, exiting..." + exit(0) +@@ -247,7 +283,7 @@ + if os.path.basename(test.name) in self.ini["disabled"]: + print "[ skip ]" + else: +- test.run(server) ++ test.run() + if not test.passed(): + failed_tests.append(test.name) + +@@ -255,11 +291,9 @@ + if len(failed_tests): + print "Failed {0} tests: {1}.".format(len(failed_tests), + ", ".join(failed_tests)) +- server.stop(silent=False) +- server.cleanup() ++ server.stop(); + +- if self.args.valgrind and check_valgrind_log(server.valgrind_log): ++ if self.args.valgrind and check_valgrind_log(self.ini["valgrind_log"]): + print " Error! There were warnings/errors in valgrind log file:" +- print_tail_n(server.valgrind_log, 20) +- return 1 +- return len(failed_tests) ++ print_tail_n(self.ini["valgrind_log"], 20) ++ diff --git a/databases/tarantool/files/patch-test_tarantool b/databases/tarantool/files/patch-test_tarantool new file mode 100644 index 000000000000..21db488e780c --- /dev/null +++ b/databases/tarantool/files/patch-test_tarantool @@ -0,0 +1,30 @@ +--- test/tarantool.orig 2011-05-14 12:16:32.000000000 +0000 ++++ test/tarantool 2011-12-13 01:12:12.696699437 +0000 +@@ -1,4 +1,4 @@ +-#! /usr/bin/python ++#! /usr/bin/env python + """A simplistic client for tarantool/silverbox: administrative + console and SQL client. + +@@ -32,8 +32,8 @@ + import socket + import sys + import string +-from lib.tarantool_admin import TarantoolAdmin, is_admin_re +-from lib.box import Box ++from lib.tarantool_connection import AdminConnection, DataConnection, \ ++ is_admin_re + + class Options: + def __init__(self): +@@ -94,8 +94,8 @@ + def main(): + init_readline_history() + options = Options() +- admin_con = TarantoolAdmin(options.args.host, options.args.admin_port) +- data_con = Box(options.args.host, options.args.port) ++ admin_con = AdminConnection(options.args.host, options.args.admin_port) ++ data_con = DataConnection(options.args.host, options.args.port) + try: + admin_con.connect() + data_con.connect() diff --git a/databases/tarantool/files/pkg-message.in b/databases/tarantool/files/pkg-message.in new file mode 100644 index 000000000000..53ca686eb6c7 --- /dev/null +++ b/databases/tarantool/files/pkg-message.in @@ -0,0 +1,10 @@ +######################################################### +# +# +# After install you'll need init storage: +# +# %%PREFIX%%/bin/tarantool_silverbox --init-storage \ +# -c %%ETCDIR%%/tarantool.cfg +# +# +######################################################### diff --git a/databases/tarantool/files/tarantool.in b/databases/tarantool/files/tarantool.in new file mode 100644 index 000000000000..65383b03acbf --- /dev/null +++ b/databases/tarantool/files/tarantool.in @@ -0,0 +1,29 @@ +#!/bin/sh +# +# $FreeBSD$ + +# PROVIDE: tarantool +# REQUIRE: LOGIN +# KEYWORD: shutdown +# +# tarantool_enable="YES" +# tarantool_config="" +# + +. /etc/rc.subr + +name="tarantool" + +tarantool_enable=${tarantool_enable:-"NO"} +tarantool_config=${tarantool_config:-"%%ETCDIR%%/$name.cfg"} + +rcvar=`set_rcvar` + +load_rc_config "$name" + +command="%%PREFIX%%/bin/tarantool_silverbox" +command_args="--daemonize --config ${tarantool_config}" +pidfile="/var/run/$name.pid" + +run_rc_command "$1" + diff --git a/databases/tarantool/pkg-descr b/databases/tarantool/pkg-descr new file mode 100644 index 000000000000..720806dee134 --- /dev/null +++ b/databases/tarantool/pkg-descr @@ -0,0 +1,5 @@ +Tarantool/Box, or simply Tarantool, is a high performance key/value +storage server. The code is available for free under the terms of +BSD license. Supported platforms are GNU/Linux and FreeBSD. + +WWW: http://tarantool.org/ diff --git a/databases/tarantool/pkg-plist b/databases/tarantool/pkg-plist new file mode 100644 index 000000000000..763fbd12d6f1 --- /dev/null +++ b/databases/tarantool/pkg-plist @@ -0,0 +1,21 @@ +bin/lib/__init__.py +bin/lib/sql.g +bin/lib/sql.py +bin/lib/sql_ast.py +bin/lib/tarantool_connection.py +bin/lib/tarantool_preprocessor.py +bin/lib/tarantool_silverbox_server.py +bin/lib/test_suite.py +bin/lib/yapps/__init__.py +bin/lib/yapps/runtime.py +bin/tarantool +bin/tarantool_feeder +bin/tarantool_silverbox +%%DOCSDIR%%/LICENSE +%%DOCSDIR%%/README +%%DOCSDIR%%/silverbox-protocol.txt +%%ETCDIR%%/tarantool.cfg +@dirrm %%DOCSDIR%% +@dirrm %%ETCDIR%% +@dirrm bin/lib/yapps +@dirrm bin/lib |