From 927e9dbf45e421eb46a7726690693696555ff666 Mon Sep 17 00:00:00 2001
From: Roman Tokarev <rtokarev@corp.mail.ru>
Date: Tue, 5 Apr 2011 17:02:18 +0400
Subject: [PATCH] Update files generated by confetti. Port tarantool to
 ObjectiveC. Implement basic TNTException class and  TNTFiberException and
 TNTBoxException subclasses. Replace longjmp/setjmp with ObjectiveC
 exceptions.

mod/box: Restructurize request processing in the following way:

	try
		begin
		dispatch
		commit
	catch
		abort

where any error during request processing generate an exception.
---
 CMakeLists.txt                            |  10 +-
 cfg/CMakeLists.txt                        |   4 +-
 cfg/prscfg.c                              |   9 +-
 cfg/tarantool_box_cfg.c                   |   3 +-
 cfg/tarantool_feeder_cfg.c                |   3 +-
 cfg/warning.c                             |   6 +-
 cfg/warning.h                             |   8 +
 core/CMakeLists.txt                       |  36 +-
 core/{admin.c => admin.m}                 |   0
 core/{coro.c => coro.m}                   |   0
 core/{diagnostics.c => diagnostics.m}     |   1 +
 core/exceptions.m                         |  34 ++
 core/{fiber.c => fiber.m}                 |  22 +-
 core/{iproto.c => iproto.m}               |   0
 core/{log_io.c => log_io.m}               | 139 ++++---
 core/{log_io_remote.c => log_io_remote.m} |  12 -
 core/{palloc.c => palloc.m}               |   0
 core/{pickle.c => pickle.m}               |  39 +-
 core/{salloc.c => salloc.m}               |   0
 core/{say.c => say.m}                     |   0
 core/{stat.c => stat.m}                   |   0
 core/{tarantool.c => tarantool.m}         |   3 +-
 core/{tarantool_ev.c => tarantool_ev.m}   |   0
 core/{tbuf.c => tbuf.m}                   |   0
 core/{trace.c => trace.m}                 |   0
 core/{util.c => util.m}                   |   0
 include/exceptions.h                      |  16 +
 include/fiber.h                           |  17 +-
 include/pickle.h                          |   4 +
 include/tarantool.h                       |   1 -
 mod/box/CMakeLists.txt                    |  12 +-
 mod/box/box.h                             |  33 +-
 mod/box/{box.c => box.m}                  | 445 ++++++++++++----------
 mod/box/index.h                           |   2 +-
 mod/box/{index.c => index.m}              |   4 +-
 mod/box/{memcached.c => memcached.m}      |   4 +-
 mod/box/memcached.rl                      |   4 +-
 mod/feeder/CMakeLists.txt                 |   2 +-
 mod/feeder/{feeder.c => feeder.m}         |   0
 39 files changed, 494 insertions(+), 379 deletions(-)
 rename core/{admin.c => admin.m} (100%)
 rename core/{coro.c => coro.m} (100%)
 rename core/{diagnostics.c => diagnostics.m} (98%)
 create mode 100644 core/exceptions.m
 rename core/{fiber.c => fiber.m} (97%)
 rename core/{iproto.c => iproto.m} (100%)
 rename core/{log_io.c => log_io.m} (95%)
 rename core/{log_io_remote.c => log_io_remote.m} (97%)
 rename core/{palloc.c => palloc.m} (100%)
 rename core/{pickle.c => pickle.m} (85%)
 rename core/{salloc.c => salloc.m} (100%)
 rename core/{say.c => say.m} (100%)
 rename core/{stat.c => stat.m} (100%)
 rename core/{tarantool.c => tarantool.m} (99%)
 rename core/{tarantool_ev.c => tarantool_ev.m} (100%)
 rename core/{tbuf.c => tbuf.m} (100%)
 rename core/{trace.c => trace.m} (100%)
 rename core/{util.c => util.m} (100%)
 create mode 100644 include/exceptions.h
 rename mod/box/{box.c => box.m} (89%)
 rename mod/box/{index.c => index.m} (99%)
 rename mod/box/{memcached.c => memcached.m} (99%)
 rename mod/feeder/{feeder.c => feeder.m} (100%)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee9f9944fc..29228c13c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -77,7 +77,7 @@ set (CMAKE_C_FLAGS_RELEASE "-DNDEBUG -DNVALGRIND")
 #
 # Enable 'make TAGS' target.
 #
-add_custom_target(TAGS COMMAND ctags -R -e -f TAGS
+add_custom_target(TAGS COMMAND ctags -R --langmap=ObjectiveC:.m.h -e -f TAGS
     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
 
 #
@@ -180,6 +180,14 @@ if (ENABLE_STATIC)
     set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static")
 endif()
 
+# CMake believes that Objective C is a flavor of C++, not C,
+# and uses g++ compiler for .m files. Since talking CMake out
+# of this idea is difficult, and since gcc or g++ are only
+# front-ends to the language-specific compiler specified in
+# -x option, simply use CXX flags to build Objective C files.
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS}")
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
 
 add_subdirectory(third_party)
 add_subdirectory(cfg)
diff --git a/cfg/CMakeLists.txt b/cfg/CMakeLists.txt
index a13e8e0254..cd5fc2e574 100644
--- a/cfg/CMakeLists.txt
+++ b/cfg/CMakeLists.txt
@@ -10,7 +10,7 @@ add_custom_command(
     OUTPUT ${CMAKE_SOURCE_DIR}/cfg/prscfg.h
            ${CMAKE_SOURCE_DIR}/cfg/prscfg.c
     COMMAND ${ECHO} '%{' > tmp.cfg
-    COMMAND ${CAT} ${CMAKE_SOURCE_DIR}/cfg/warning.h >> tmp.cfg
+    COMMAND ${ECHO} '\#include \"cfg/warning.h\"' >> tmp.cfg
     COMMAND ${ECHO} '%}' >> tmp.cfg
     COMMAND ${CAT} ${CMAKE_SOURCE_DIR}/cfg/core_cfg.cfg_tmpl >> tmp.cfg
     COMMAND ${CONFETTI} -i tmp.cfg -n tarantool_cfg
@@ -37,7 +37,7 @@ add_custom_command(
            ${CMAKE_SOURCE_DIR}/cfg/tarantool_${mod}_cfg.c
            ${CMAKE_SOURCE_DIR}/cfg/tarantool_${mod}_cfg.cfg
     COMMAND ${ECHO} '%{' > ${mod}_tmp.cfg
-    COMMAND ${CAT} ${CMAKE_SOURCE_DIR}/cfg/warning.h >> ${mod}_tmp.cfg
+    COMMAND ${ECHO} '\#include \"cfg/warning.h\"' >> ${mod}_tmp.cfg
     COMMAND ${ECHO} '\#include \"cfg/tarantool_${mod}_cfg.h\"' >> ${mod}_tmp.cfg
     COMMAND ${ECHO} '%}' >> ${mod}_tmp.cfg
     COMMAND ${CAT} ${CMAKE_SOURCE_DIR}/cfg/core_cfg.cfg_tmpl >> ${mod}_tmp.cfg
diff --git a/cfg/prscfg.c b/cfg/prscfg.c
index cc4ef3a14f..6f930b537c 100644
--- a/cfg/prscfg.c
+++ b/cfg/prscfg.c
@@ -1,6 +1,5 @@
 
-#include "prscfg.h"
-void out_warning(ConfettyError r, char *format, ...);
+#include "cfg/warning.h"
 #include <stdio.h>
 
 typedef struct prscfg_yy_extra_type {
@@ -1770,7 +1769,7 @@ YYSTYPE yylval;
 /* Line 1455 of yacc.c  */
 #line 173 "prscfg.y"
     {
-			OptDef	*str;
+			OptDef		*str;
 			NameAtom	*idx;
 
 			MakeAtom(idx, NULL);
@@ -1787,7 +1786,7 @@ YYSTYPE yylval;
 /* Line 1455 of yacc.c  */
 #line 184 "prscfg.y"
     {
-			OptDef	*str;
+			OptDef		*str;
 			NameAtom	*idx;
 
 			MakeAtom(idx, NULL);
@@ -2100,7 +2099,7 @@ compileName(OptDef	*def) {
 				return 1;
 
 			if (index >= 0) {
-				beginPtr->index = index;
+				endPtr->index = index;
 				index = -1;
 			}
 
diff --git a/cfg/tarantool_box_cfg.c b/cfg/tarantool_box_cfg.c
index 7218b9624b..deea203080 100644
--- a/cfg/tarantool_box_cfg.c
+++ b/cfg/tarantool_box_cfg.c
@@ -11,8 +11,7 @@
  */
 
 
-#include "prscfg.h"
-void out_warning(ConfettyError r, char *format, ...);
+#include "cfg/warning.h"
 #include "cfg/tarantool_box_cfg.h"
 static int
 cmpNameAtoms(NameAtom *a, NameAtom *b) {
diff --git a/cfg/tarantool_feeder_cfg.c b/cfg/tarantool_feeder_cfg.c
index 6719ca8a8e..654730105b 100644
--- a/cfg/tarantool_feeder_cfg.c
+++ b/cfg/tarantool_feeder_cfg.c
@@ -11,8 +11,7 @@
  */
 
 
-#include "prscfg.h"
-void out_warning(ConfettyError r, char *format, ...);
+#include "cfg/warning.h"
 #include "cfg/tarantool_feeder_cfg.h"
 static int
 cmpNameAtoms(NameAtom *a, NameAtom *b) {
diff --git a/cfg/warning.c b/cfg/warning.c
index 0075f778e7..c3887e92ed 100644
--- a/cfg/warning.c
+++ b/cfg/warning.c
@@ -1,8 +1,10 @@
 #include "warning.h"
+
+#include <tbuf.h>
+
 #include <stdarg.h>
 
-#include <tarantool.h>
-#include <util.h>
+struct tbuf *cfg_out = NULL;
 
 /** This is a callback function used by the generated
  * configuration file parser (tarantool_{box, feeder, ...}_cfg.c)
diff --git a/cfg/warning.h b/cfg/warning.h
index 3898f77987..58792abe3a 100644
--- a/cfg/warning.h
+++ b/cfg/warning.h
@@ -1,2 +1,10 @@
+#ifndef TARANTOOL_WARNING_H
+#define TARANTOOL_WARNING_H
+
 #include "prscfg.h"
+
+extern struct tbuf *cfg_out;
+
 void out_warning(ConfettyError r, char *format, ...);
+
+#endif
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 9ccc809a0f..1c59e887b9 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -1,12 +1,12 @@
 #
 # libev library
 #
-add_library(ev tarantool_ev.c)
+add_library(ev tarantool_ev.m)
 
 check_c_compiler_flag ("-Wno-unused-result" gcc_has_wno_unused_result)
 
 if (gcc_has_wno_unused_result)
-    set_source_files_properties(tarantool_ev.c
+    set_source_files_properties(tarantool_ev.m
         PROPERTIES COMPILE_FLAGS "-Wno-unused-result")
 endif()
 
@@ -25,21 +25,21 @@ endif()
 target_link_libraries(ev m)
 
 #
-# Build admin.c from admin.rl, but only if admin.rl was changed.
-# The same applies to memcached.c/memcached.rl.
-# We track admin.c and memcached.c in revision control, and thus do not
+# Build admin.m from admin.rl, but only if admin.rl was changed.
+# The same applies to memcached.m/memcached.rl.
+# We track admin.m and memcached.m in revision control, and thus do not
 # require engineers who do not modify .rl files to have Ragel
 # installed.
 #
-add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/core/admin.c
+add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/core/admin.m
     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-    COMMAND ${RAGEL} -G2 core/admin.rl -o core/admin.c
+    COMMAND ${RAGEL} -G2 core/admin.rl -o core/admin.m
     DEPENDS ${CMAKE_SOURCE_DIR}/core/admin.rl)
 
-add_custom_target(generate_admin_c DEPENDS ${CMAKE_SOURCE_DIR}/core/admin.c)
+add_custom_target(generate_admin_c DEPENDS ${CMAKE_SOURCE_DIR}/core/admin.m)
 
 #
-# Do not clean admin.c, memcached.c or other
+# Do not clean admin.m, memcached.m or other
 # generated files in 'make clean' -- they are under
 # revision control.
 #
@@ -49,24 +49,24 @@ set_property(DIRECTORY PROPERTY CLEAN_NO_CUSTOM 1)
 # Used by modules.
 #
 set (recompiled_core_sources
-     ${CMAKE_SOURCE_DIR}/core/tarantool.c
-     ${CMAKE_SOURCE_DIR}/core/say.c
-     ${CMAKE_SOURCE_DIR}/core/admin.c
-     ${CMAKE_SOURCE_DIR}/core/fiber.c PARENT_SCOPE)
+     ${CMAKE_SOURCE_DIR}/core/tarantool.m
+     ${CMAKE_SOURCE_DIR}/core/say.m
+     ${CMAKE_SOURCE_DIR}/core/admin.m
+     ${CMAKE_SOURCE_DIR}/core/fiber.m PARENT_SCOPE)
 
-set (common_sources tbuf.c palloc.c util.c diagnostics.c
-    salloc.c pickle.c coro.c stat.c log_io.c
-    log_io_remote.c iproto.c)
+set (common_sources tbuf.m palloc.m util.m diagnostics.m
+    salloc.m pickle.m coro.m stat.m log_io.m
+    log_io_remote.m iproto.m exceptions.m)
 
 if (ENABLE_TRACE)
-  set (common_sources ${common_sources} trace.c)
+  set (common_sources ${common_sources} trace.m)
 endif()
 
 add_library(core STATIC ${common_sources})
 add_dependencies(core generate_headers)
 set_target_properties(core PROPERTIES COMPILE_FLAGS "${core_cflags}")
 
-set (common_libraries cfg core ev coro gopt misc)
+set (common_libraries cfg core ev coro gopt misc objc)
 
 if (ENABLE_GCOV)
   set (common_libraries ${common_libraries} gcov)
diff --git a/core/admin.c b/core/admin.m
similarity index 100%
rename from core/admin.c
rename to core/admin.m
diff --git a/core/coro.c b/core/coro.m
similarity index 100%
rename from core/coro.c
rename to core/coro.m
diff --git a/core/diagnostics.c b/core/diagnostics.m
similarity index 98%
rename from core/diagnostics.c
rename to core/diagnostics.m
index 7a6e6a2445..3266ae52a0 100644
--- a/core/diagnostics.c
+++ b/core/diagnostics.m
@@ -88,4 +88,5 @@ struct Error *diag_get_last_error()
 void diag_clear()
 {
 	error_destroy(fiber->diagnostics);
+	fiber->diagnostics = NULL;
 }
diff --git a/core/exceptions.m b/core/exceptions.m
new file mode 100644
index 0000000000..45eaacf81b
--- /dev/null
+++ b/core/exceptions.m
@@ -0,0 +1,34 @@
+#include <exceptions.h>
+
+@implementation TNTException
++(id) withReason:(const char *)str
+{
+	static id e = nil;
+
+	if (![e isKindOf:self]) {
+		[e free];
+		e = [[self alloc] init];
+	}
+
+	return [e setReason:str];
+}
+
+-(void) init
+{
+	[super init];
+
+	reason = "";
+}
+
+-(TNTException *) setReason:(const char *)str
+{
+	reason = str;
+
+	return self;
+}
+
+-(const char *) Reason
+{
+	return reason;
+}
+@end
diff --git a/core/fiber.c b/core/fiber.m
similarity index 97%
rename from core/fiber.c
rename to core/fiber.m
index 690f4f7557..b0645334f7 100644
--- a/core/fiber.c
+++ b/core/fiber.m
@@ -56,6 +56,9 @@
 #include <pickle.h>
 #include "diagnostics.h"
 
+@implementation TNTFiberException
+@end
+
 static struct fiber sched;
 struct fiber *fiber = &sched;
 static struct fiber **sp, *call_stack[64];
@@ -342,10 +345,20 @@ fiber_loop(void *data __attribute__((unused)))
 {
 	while (42) {
 		assert(fiber != NULL && fiber->f != NULL && fiber->fid != 0);
-		if (setjmp(fiber->exc) == 0) {
+		@try {
 			fiber->f(fiber->f_data);
-		} else {
-			panic("fiber %s failure, exiting", fiber->name);
+		}
+		@catch (TNTFiberException *e) {
+			say_info("fiber `%s': exception `TNTFiberException': `%s'", fiber->name, [e Reason]);
+			say_info("fiber `%s': exiting", fiber->name);
+		}
+		@catch (TNTException *e) {
+			say_error("fiber `%s': exception `%s': `%s'", fiber->name, [e name], [e Reason]);
+			panic("fiber `%s': exiting", fiber->name);
+		}
+		@catch (id e) {
+			say_error("fiber `%s': exception `%s'", fiber->name, [e name]);
+			panic("fiber `%s': exiting", fiber->name);
 		}
 
 		fiber_close();
@@ -1119,9 +1132,6 @@ fiber_info(struct tbuf *out)
 		tbuf_printf(out, "    fd: %4i" CRLF, fiber->fd);
 		tbuf_printf(out, "    peer: %s" CRLF, fiber_peer_name(fiber));
 		tbuf_printf(out, "    stack: %p" CRLF, stack_top);
-		tbuf_printf(out, "    exc: %p" CRLF,
-			    ((void **)fiber->exc)[3]);
-		tbuf_printf(out, "    exc_frame: %p,"CRLF, ((void **)fiber->exc)[3] + 2 * sizeof(void *));
 #ifdef ENABLE_BACKTRACE
 		tbuf_printf(out, "    backtrace:" CRLF "%s",
 			    backtrace(fiber->last_stack_frame,
diff --git a/core/iproto.c b/core/iproto.m
similarity index 100%
rename from core/iproto.c
rename to core/iproto.m
diff --git a/core/log_io.c b/core/log_io.m
similarity index 95%
rename from core/log_io.c
rename to core/log_io.m
index 345c8e94c4..00d3f9f5c6 100644
--- a/core/log_io.c
+++ b/core/log_io.m
@@ -903,53 +903,48 @@ recover_snap(struct recovery_state *r)
 	struct log_io_iter i;
 	struct log_io *snap = NULL;
 	struct tbuf *row;
-	int result = -1;
 	i64 lsn;
 
-	memset(&i, 0, sizeof(i));
+	@try {
+		memset(&i, 0, sizeof(i));
 
-	if (setjmp(fiber->exc) != 0) {
-		result = -1;
-		goto out;
-	}
+		lsn = greatest_lsn(r->snap_prefered_class);
+		if (lsn <= 0)
+			raise("can't find snapshot");
 
-	lsn = greatest_lsn(r->snap_prefered_class);
+		snap = open_for_read(r, r->snap_class, lsn, 0, NULL);
+		if (snap == NULL)
+			raise("can't find/open snapshot");
 
-	if (lsn <= 0) {
-		say_error("can't find snapshot");
-		goto out;
-	}
+		iter_open(snap, &i, read_rows);
+		say_info("recover from `%s'", snap->filename);
 
-	snap = open_for_read(r, r->snap_class, lsn, 0, NULL);
-	if (snap == NULL) {
-		say_error("can't find/open snapshot");
-		goto out;
-	}
+		while ((row = iter_inner(&i, (void *)1))) {
+			if (r->row_handler(r, row) < 0)
+				raise("can't apply row");
+		}
+		if (i.error != 0)
+			raise("error during snapshot processing");
 
-	iter_open(snap, &i, read_rows);
-	say_info("recover from `%s'", snap->filename);
+		r->lsn = r->confirmed_lsn = lsn;
 
-	while ((row = iter_inner(&i, (void *)1))) {
-		if (r->row_handler(r, row) < 0) {
-			result = -1;
-			goto out;
-		}
+		return 0;
 	}
-	result = i.error;
-	if (result == 0)
-		r->lsn = r->confirmed_lsn = lsn;
-      out:
-	if (result != 0)
+	@catch (TNTException *e) {
+		say_error("TNTException: `%s'", [e Reason]);
 		say_error("failure reading snapshot");
 
-	if (i.log != NULL)
-		close_iter(&i);
+		return -1;
+	}
+	@finally {
+		if (i.log != NULL)
+			close_iter(&i);
 
-	if (snap != NULL)
-		close_log(&snap);
+		if (snap != NULL)
+			close_log(&snap);
 
-	prelease(fiber->pool);
-	return result;
+		prelease(fiber->pool);
+	}
 }
 
 /*
@@ -966,56 +961,54 @@ recover_wal(struct recovery_state *r, struct log_io *l)
 {
 	struct log_io_iter i;
 	struct tbuf *row = NULL;
-	int result;
 
-	if (setjmp(fiber->exc) != 0) {
-		result = -1;
-		goto out;
-	}
+	@try {
+		memset(&i, 0, sizeof(i));
+		iter_open(l, &i, read_rows);
 
-	memset(&i, 0, sizeof(i));
-	iter_open(l, &i, read_rows);
+		while ((row = iter_inner(&i, (void *)1))) {
+			i64 lsn = row_v11(row)->lsn;
+			if (r && lsn <= r->confirmed_lsn) {
+				say_debug("skipping too young row");
+				continue;
+			}
 
-	while ((row = iter_inner(&i, (void *)1))) {
-		i64 lsn = row_v11(row)->lsn;
-		if (r && lsn <= r->confirmed_lsn) {
-			say_debug("skipping too young row");
-			continue;
-		}
+			/*  after handler(r, row) returned, row may be modified, do not use it */
+			if (r->row_handler(r, row) < 0)
+				raise("can't apply row");
 
-		/*  after handler(r, row) returned, row may be modified, do not use it */
-		if (r->row_handler(r, row) < 0) {
-			say_error("row_handler returned error");
-			result = -1;
-			goto out;
+			if (r) {
+				next_lsn(r, lsn);
+				confirm_lsn(r, lsn);
+			}
 		}
 
-		if (r) {
-			next_lsn(r, lsn);
-			confirm_lsn(r, lsn);
-		}
-	}
-	result = i.error;
-      out:
-	/*
-	 * since we don't close log_io
-	 * we must rewind log_io to last known
-	 * good position if where was error
-	 */
-	if (row)
-		iter_inner(&i, NULL);
+		if (i.error != 0)
+			raise("error during xlog processing");
 
-	if (result == 0) {
 		if (i.eof)
-			result = LOG_EOF;
-		else
-			result = 1;
+			return LOG_EOF;
+
+		return 1;
 	}
+	@catch (TNTException *e) {
+		say_error("TNTException: `%s'", [e Reason]);
+		say_error("failure reading xlog");
 
-	close_iter(&i);
-	prelease(fiber->pool);
+		return -1;
+	}
+	@finally {
+		/*
+		 * since we don't close log_io
+		 * we must rewind log_io to last known
+		 * good position if where was error
+		 */
+		if (row)
+			iter_inner(&i, NULL);
 
-	return result;
+		close_iter(&i);
+		prelease(fiber->pool);
+	}
 }
 
 /*
diff --git a/core/log_io_remote.c b/core/log_io_remote.m
similarity index 97%
rename from core/log_io_remote.c
rename to core/log_io_remote.m
index 7201582979..db02df43c0 100644
--- a/core/log_io_remote.c
+++ b/core/log_io_remote.m
@@ -133,18 +133,6 @@ pull_from_remote(void *state)
 	struct remote_state *h = state;
 	struct tbuf *row;
 
-	switch (setjmp(fiber->exc)) {
-		case 0:
-			break;
-
-		case FIBER_EXIT:
-			fiber_close();
-			return;
-
-		default:
-			fiber_close();
-	}
-
 	for (;;) {
 		row = remote_read_row(h->r->confirmed_lsn + 1);
 		h->r->recovery_lag = ev_now() - row_v11(row)->tm;
diff --git a/core/palloc.c b/core/palloc.m
similarity index 100%
rename from core/palloc.c
rename to core/palloc.m
diff --git a/core/pickle.c b/core/pickle.m
similarity index 85%
rename from core/pickle.c
rename to core/pickle.m
index 013c5fe6ba..5185e32e33 100644
--- a/core/pickle.c
+++ b/core/pickle.m
@@ -30,6 +30,11 @@
 #include <iproto.h>		/* for err codes */
 #include "say.h"
 
+#define pickle_raise(reason...) @throw [TNTPickleException withReason:reason"\0"]
+
+@implementation TNTPickleException
+@end
+
 /* caller must ensure that there is space in target */
 u8 *
 save_varint32(u8 *target, u32 value)
@@ -76,16 +81,16 @@ write_varint32(struct tbuf *b, u32 value)
 	append_byte(b, (u8)((value) & 0x7F));
 }
 
-#define read_u(bits)							\
-	u##bits read_u##bits(struct tbuf *b)				\
-	{								\
-		if (b->len < (bits)/8)					\
-			raise(ERR_CODE_UNKNOWN_ERROR, "buffer too short"); \
-		u##bits r = *(u##bits *)b->data;			\
-		b->size -= (bits)/8;					\
-		b->len -= (bits)/8;					\
-		b->data += (bits)/8;					\
-		return r;						\
+#define read_u(bits)					  \
+	u##bits read_u##bits(struct tbuf *b)		  \
+	{						  \
+		if (b->len < (bits)/8)			  \
+			pickle_raise("buffer too short"); \
+		u##bits r = *(u##bits *)b->data;	  \
+		b->size -= (bits)/8;			  \
+		b->len -= (bits)/8;			  \
+		b->data += (bits)/8;			  \
+		return r;				  \
 	}
 
 read_u(8)
@@ -100,7 +105,7 @@ read_varint32(struct tbuf *buf)
 	int len = buf->len;
 
 	if (len < 1)
-		raise(ERR_CODE_UNKNOWN_ERROR, "buffer too short");
+		pickle_raise("buffer too short");
 	if (!(b[0] & 0x80)) {
 		buf->data += 1;
 		buf->size -= 1;
@@ -109,7 +114,7 @@ read_varint32(struct tbuf *buf)
 	}
 
 	if (len < 2)
-		raise(ERR_CODE_UNKNOWN_ERROR, "buffer too short");
+		pickle_raise("buffer too short");
 	if (!(b[1] & 0x80)) {
 		buf->data += 2;
 		buf->size -= 2;
@@ -117,7 +122,7 @@ read_varint32(struct tbuf *buf)
 		return (b[0] & 0x7f) << 7 | (b[1] & 0x7f);
 	}
 	if (len < 3)
-		raise(ERR_CODE_UNKNOWN_ERROR, "buffer too short");
+		pickle_raise("buffer too short");
 	if (!(b[2] & 0x80)) {
 		buf->data += 3;
 		buf->size -= 3;
@@ -126,7 +131,7 @@ read_varint32(struct tbuf *buf)
 	}
 
 	if (len < 4)
-		raise(ERR_CODE_UNKNOWN_ERROR, "buffer too short");
+		pickle_raise("buffer too short");
 	if (!(b[3] & 0x80)) {
 		buf->data += 4;
 		buf->size -= 4;
@@ -136,7 +141,7 @@ read_varint32(struct tbuf *buf)
 	}
 
 	if (len < 5)
-		raise(ERR_CODE_UNKNOWN_ERROR, "buffer too short");
+		pickle_raise("buffer too short");
 	if (!(b[4] & 0x80)) {
 		buf->data += 5;
 		buf->size -= 5;
@@ -145,7 +150,7 @@ read_varint32(struct tbuf *buf)
 			(b[2] & 0x7f) << 14 | (b[3] & 0x7f) << 7 | (b[4] & 0x7f);
 	}
 
-	raise(ERR_CODE_UNKNOWN_ERROR, "impossible happened");
+	pickle_raise("impossible happened");
 	return 0;
 }
 
@@ -165,7 +170,7 @@ read_field(struct tbuf *buf)
 	u32 data_len = read_varint32(buf);
 
 	if (data_len > buf->len)
-		raise(ERR_CODE_UNKNOWN_ERROR, "buffer too short");
+		pickle_raise("buffer too short");
 
 	buf->size -= data_len;
 	buf->len -= data_len;
diff --git a/core/salloc.c b/core/salloc.m
similarity index 100%
rename from core/salloc.c
rename to core/salloc.m
diff --git a/core/say.c b/core/say.m
similarity index 100%
rename from core/say.c
rename to core/say.m
diff --git a/core/stat.c b/core/stat.m
similarity index 100%
rename from core/stat.c
rename to core/stat.m
diff --git a/core/tarantool.c b/core/tarantool.m
similarity index 99%
rename from core/tarantool.c
rename to core/tarantool.m
index 1450e582ad..d14b975cd5 100644
--- a/core/tarantool.c
+++ b/core/tarantool.m
@@ -53,13 +53,13 @@
 #include TARANTOOL_CONFIG
 #include <util.h>
 #include <third_party/gopt/gopt.h>
+#include <cfg/warning.h>
 
 
 static pid_t master_pid;
 #define DEFAULT_CFG_FILENAME "tarantool.cfg"
 const char *cfg_filename = DEFAULT_CFG_FILENAME;
 char *cfg_filename_fullpath = NULL;
-struct tbuf *cfg_out = NULL;
 char *binary_filename;
 struct tarantool_cfg cfg;
 struct recovery_state *recovery_state;
@@ -67,7 +67,6 @@ struct recovery_state *recovery_state;
 bool init_storage, booting = true;
 
 extern int daemonize(int nochdir, int noclose);
-void out_warning(int v, char *format, ...);
 
 static i32
 load_cfg(struct tarantool_cfg *conf, i32 check_rdonly)
diff --git a/core/tarantool_ev.c b/core/tarantool_ev.m
similarity index 100%
rename from core/tarantool_ev.c
rename to core/tarantool_ev.m
diff --git a/core/tbuf.c b/core/tbuf.m
similarity index 100%
rename from core/tbuf.c
rename to core/tbuf.m
diff --git a/core/trace.c b/core/trace.m
similarity index 100%
rename from core/trace.c
rename to core/trace.m
diff --git a/core/util.c b/core/util.m
similarity index 100%
rename from core/util.c
rename to core/util.m
diff --git a/include/exceptions.h b/include/exceptions.h
new file mode 100644
index 0000000000..d872055316
--- /dev/null
+++ b/include/exceptions.h
@@ -0,0 +1,16 @@
+#ifndef TARANTOOL_EXCEPTIONS_H
+#define TARANTOOL_EXCEPTIONS_H
+
+#include <objc/Object.h>
+
+@interface TNTException: Object {
+	const char *reason;
+}
+
++(id) withReason:(const char *)str;
+
+-(TNTException *) setReason:(const char *)str;
+-(const char *) Reason;
+@end
+
+#endif
diff --git a/include/fiber.h b/include/fiber.h
index 42871d6251..191bdd8d12 100644
--- a/include/fiber.h
+++ b/include/fiber.h
@@ -40,8 +40,10 @@
 #include <util.h>
 #include "third_party/queue.h"
 
+#include <exceptions.h>
 
-#define FIBER_EXIT -1
+@interface TNTFiberException: TNTException
+@end
 
 struct msg {
 	uint32_t sender_fid;
@@ -76,9 +78,6 @@ struct fiber {
 
 	struct ring *inbox;
 
-	jmp_buf exc;
-	const char *errstr;
-
 	const char *name;
 	void (*f) (void *);
 	void *f_data;
@@ -118,11 +117,11 @@ void unwait(int events);
 void yield(void);
 void raise_(int);
 void fiber_destroy_all();
-#define raise(v, err)							\
-	({								\
-		say_debug("raise 0x%x/%s at %s:%i", v, err, __FILE__, __LINE__); \
-		fiber->errstr = (err);					\
-		longjmp(fiber->exc, (v));				\
+#define raise(err...)							     \
+	({								     \
+		const char *_errstr = err"\0";				     \
+		say_debug("raise %s at %s:%i", _errstr, __FILE__, __LINE__); \
+		@throw [TNTException withReason:_errstr];		     \
 	})
 
 struct msg *read_inbox(void);
diff --git a/include/pickle.h b/include/pickle.h
index 8a51cde672..9fb718b5c6 100644
--- a/include/pickle.h
+++ b/include/pickle.h
@@ -28,6 +28,10 @@
 #include <stdbool.h>
 
 #include <util.h>
+#include <exceptions.h>
+
+@interface TNTPickleException: TNTException
+@end
 
 struct tbuf;
 
diff --git a/include/tarantool.h b/include/tarantool.h
index cc839a8eac..60cdf4032d 100644
--- a/include/tarantool.h
+++ b/include/tarantool.h
@@ -42,7 +42,6 @@ void mod_exec(char *str, int len, struct tbuf *out);
 
 extern struct tarantool_module module;
 extern struct tarantool_cfg cfg;
-extern struct tbuf *cfg_out;
 extern const char *cfg_filename;
 extern bool init_storage, booting;
 extern char *binary_filename;
diff --git a/mod/box/CMakeLists.txt b/mod/box/CMakeLists.txt
index f92e265ecd..7d0af32b5d 100644
--- a/mod/box/CMakeLists.txt
+++ b/mod/box/CMakeLists.txt
@@ -1,11 +1,11 @@
-add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/mod/box/memcached.c
+add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/mod/silverbox/memcached.m
     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-    COMMAND ${RAGEL} -G2 mod/box/memcached.rl -o mod/box/memcached.c
-    DEPENDS ${CMAKE_SOURCE_DIR}/mod/box/memcached.rl)
-# Do not clean memcached.c in 'make clean'.
+    COMMAND ${RAGEL} -G2 mod/silverbox/memcached.rl -o mod/silverbox/memcached.m
+    DEPENDS ${CMAKE_SOURCE_DIR}/mod/silverbox/memcached.rl)
+# Do not clean memcached.m in 'make clean'.
 set_property(DIRECTORY PROPERTY CLEAN_NO_CUSTOM 1)
 
-set_source_files_properties(memcached.c
+set_source_files_properties(memcached.m
     PROPERTIES COMPILE_FLAGS "-Wno-uninitialized")
 
-tarantool_module("box" index.c box.c memcached.c)
+tarantool_module("box" index.m box.m memcached.m)
diff --git a/mod/box/box.h b/mod/box/box.h
index ba2a470b58..5a3de9b17e 100644
--- a/mod/box/box.h
+++ b/mod/box/box.h
@@ -27,6 +27,18 @@
  */
 
 #include <mod/box/index.h>
+#include <exceptions.h>
+#include <tbuf.h>
+
+@interface TNTBoxException: TNTException {
+	u32 value;
+}
+
++(id) withReason:(const char *)str withValue:(u32)val;
+
+-(TNTBoxException *) setValue:(u32)val;
+-(u32) Value;
+@end
 
 extern bool box_updates_allowed;
 void memcached_handler(void * /* data */);
@@ -57,7 +69,7 @@ struct box_tuple {
 } __attribute__((packed));
 
 struct box_txn {
-	int op;
+	u16 op;
 	u32 flags;
 
 	struct namespace *namespace;
@@ -69,7 +81,11 @@ struct box_txn {
 	struct box_tuple *tuple;
 	struct box_tuple *lock_tuple;
 
+	size_t saved_iov_cnt;
+	struct tbuf req;
+
 	bool in_recover;
+	bool write_to_wal;
 };
 
 enum tuple_flags {
@@ -117,16 +133,17 @@ enum box_mode {
 
 ENUM(messages, MESSAGES);
 
-#define box_raise(n, err)						\
-	({								\
-		if (n != ERR_CODE_NODE_IS_RO)				\
-			say_warn("%s/%s", error_codes_strs[(n)], err);	\
-		raise(n, err);						\
+#define box_raise(n, err...)						   \
+	({								   \
+		const char *_errstr = err"\0";				   \
+		if (n != ERR_CODE_NODE_IS_RO)				   \
+			say_warn("%s/%s", error_codes_strs[(n)], _errstr); \
+		@throw [TNTBoxException withReason:_errstr withValue:n];   \
 	})
 
 struct box_txn *txn_alloc(u32 flags);
-u32 box_dispatch(struct box_txn *txn, enum box_mode mode, u16 op,
-		 struct tbuf *data);
+u32 box_process(struct box_txn *txn, u32 op, enum box_mode mode, struct tbuf *request_data);
+
 void tuple_txn_ref(struct box_txn *txn, struct box_tuple *tuple);
 void txn_cleanup(struct box_txn *txn);
 
diff --git a/mod/box/box.c b/mod/box/box.m
similarity index 89%
rename from mod/box/box.c
rename to mod/box/box.m
index d501e85b5d..2eb6a46ccd 100644
--- a/mod/box/box.c
+++ b/mod/box/box.m
@@ -81,6 +81,32 @@ struct box_snap_row {
 	u8 data[];
 } __attribute__((packed));
 
+@implementation TNTBoxException
++(id) withReason:(char *)str withValue:(u32)val
+{
+	return [[self withReason:str] setValue:val];
+}
+
+-(void) init
+{
+	[super init];
+
+	value = ERR_CODE_UNKNOWN_ERROR;
+}
+
+-(TNTBoxException *) setValue:(u32)val
+{
+	value = val;
+
+	return self;
+}
+
+-(u32) Value
+{
+	return value;
+}
+@end
+
 static inline struct box_snap_row *
 box_snap_row(const struct tbuf *t)
 {
@@ -229,7 +255,7 @@ tuple_txn_ref(struct box_txn *txn, struct box_tuple *tuple)
 	tuple_ref(tuple, +1);
 }
 
-static int __attribute__((noinline))
+static void __attribute__((noinline))
 prepare_replace(struct box_txn *txn, size_t cardinality, struct tbuf *data)
 {
 	assert(data != NULL);
@@ -290,14 +316,19 @@ prepare_replace(struct box_txn *txn, size_t cardinality, struct tbuf *data)
 			index->replace(index, NULL, txn->tuple);
 	}
 
-	return -1;
+	if (!(txn->flags & BOX_QUIET) && !txn->in_recover) {
+		u32 tuples_affected = 1;
+
+		add_iov_dup(&tuples_affected, sizeof(uint32_t));
+
+		if (txn->flags & BOX_RETURN_TUPLE)
+			tuple_add_iov(txn, txn->tuple);
+	}
 }
 
 static void
 commit_replace(struct box_txn *txn)
 {
-	int tuples_affected = 1;
-
 	if (txn->old_tuple != NULL) {
 		foreach_index(txn->n, index)
 			index->replace(index, txn->old_tuple, txn->tuple);
@@ -305,14 +336,9 @@ commit_replace(struct box_txn *txn)
 		tuple_ref(txn->old_tuple, -1);
 	}
 
-	txn->tuple->flags &= ~GHOST;
-	tuple_ref(txn->tuple, +1);
-
-	if (!(txn->flags & BOX_QUIET) && !txn->in_recover) {
-		add_iov_dup(&tuples_affected, sizeof(uint32_t));
-
-		if (txn->flags & BOX_RETURN_TUPLE)
-			tuple_add_iov(txn, txn->tuple);
+	if (txn->tuple != NULL) {
+		txn->tuple->flags &= ~GHOST;
+		tuple_ref(txn->tuple, +1);
 	}
 }
 
@@ -430,7 +456,7 @@ do_field_splice(struct tbuf *field, void *args_data, u32 args_data_size)
 	*field = *new_field;
 }
 
-static int __attribute__((noinline))
+static void __attribute__((noinline))
 prepare_update_fields(struct box_txn *txn, struct tbuf *data)
 {
 	struct tbuf **fields;
@@ -438,6 +464,7 @@ prepare_update_fields(struct box_txn *txn, struct tbuf *data)
 	int i;
 	void *key;
 	u32 op_cnt;
+	u32 tuples_affected = 1;
 
 	u32 key_len = read_u32(data);
 	if (key_len != 1)
@@ -454,11 +481,11 @@ prepare_update_fields(struct box_txn *txn, struct tbuf *data)
 
 	txn->old_tuple = txn->index->find(txn->index, key);
 	if (txn->old_tuple == NULL) {
-		if (!txn->in_recover) {
-			int tuples_affected = 0;
-			add_iov_dup(&tuples_affected, sizeof(uint32_t));
-		}
-		return ERR_CODE_OK;
+		txn->write_to_wal = false;
+
+		tuples_affected = 0;
+
+		goto out;
 	}
 
 	lock_tuple(txn, txn->old_tuple);
@@ -534,7 +561,14 @@ prepare_update_fields(struct box_txn *txn, struct tbuf *data)
 
 	if (data->len != 0)
 		box_raise(ERR_CODE_ILLEGAL_PARAMS, "can't unpack request");
-	return -1;
+
+out:
+	if (!(txn->flags & BOX_QUIET) && !txn->in_recover) {
+		add_iov_dup(&tuples_affected, sizeof(uint32_t));
+
+		if (txn->flags & BOX_RETURN_TUPLE)
+			tuple_add_iov(txn, txn->tuple);
+	}
 }
 
 static void
@@ -554,7 +588,7 @@ tuple_add_iov(struct box_txn *txn, struct box_tuple *tuple)
 	}
 }
 
-static int __attribute__((noinline))
+static void __attribute__((noinline))
 process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
 {
 	struct box_tuple *tuple;
@@ -573,7 +607,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
 
 			/* End the loop if reached the limit. */
 			if (limit == *found)
-				goto end;
+				return;
 
 			u32 key_len = read_u32(data);
 			void *key = read_field(data);
@@ -606,7 +640,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
 
 			/* End the loop if reached the limit. */
 			if (limit == *found)
-				goto end;
+				return;
 
 			u32 key_len = read_u32(data);
 			if (key_len != 1)
@@ -629,43 +663,43 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data)
 
 	if (data->len != 0)
 		box_raise(ERR_CODE_ILLEGAL_PARAMS, "can't unpack request");
-
-end:
-	return ERR_CODE_OK;
 }
 
-static int __attribute__((noinline))
+static void __attribute__((noinline))
 prepare_delete(struct box_txn *txn, void *key)
 {
+	u32 tuples_affected = 0;
+
 	txn->old_tuple = txn->index->find(txn->index, key);
 
-	if (txn->old_tuple == NULL) {
-		if (!txn->in_recover) {
-			u32 tuples_affected = 0;
-			add_iov_dup(&tuples_affected, sizeof(tuples_affected));
-		}
-		return ERR_CODE_OK;
-	} else {
+	if (txn->old_tuple == NULL)
+		txn->write_to_wal = false;
+	else {
 		tuple_txn_ref(txn, txn->old_tuple);
+		lock_tuple(txn, txn->old_tuple);
+
+		tuples_affected = 1;
 	}
 
-	lock_tuple(txn, txn->old_tuple);
-	return -1;
+	if (!(txn->flags & BOX_QUIET) && !txn->in_recover)
+		add_iov_dup(&tuples_affected, sizeof(tuples_affected));
 }
 
 static void
 commit_delete(struct box_txn *txn)
 {
-	if (!(txn->flags & BOX_QUIET) && !txn->in_recover) {
-		int tuples_affected = 1;
-		add_iov_dup(&tuples_affected, sizeof(tuples_affected));
-	}
+	if (txn->old_tuple == NULL)
+		return;
 
 	foreach_index(txn->n, index)
 		index->remove(index, txn->old_tuple);
 	tuple_ref(txn->old_tuple, -1);
+}
 
-	return;
+static bool
+op_is_select(u32 op)
+{
+	return op == SELECT || op == SELECT_LIMIT;
 }
 
 struct box_txn *
@@ -674,9 +708,37 @@ txn_alloc(u32 flags)
 	struct box_txn *txn = p0alloc(fiber->pool, sizeof(*txn));
 	txn->ref_tuples = tbuf_alloc(fiber->pool);
 	txn->flags |= flags;	/* note - select will overwrite this flags */
+	txn->write_to_wal = true;
 	return txn;
 }
 
+static void
+txn_begin(struct box_txn *txn, enum box_mode mode, u16 op, struct tbuf *data)
+{
+	txn->saved_iov_cnt = fiber->iov_cnt;
+
+	if (!txn->in_recover) {
+		if (!op_is_select(op) && (mode == RO || !box_updates_allowed)) {
+			say_error("can't process %i command on RO port", op);
+			box_raise(ERR_CODE_NONMASTER);
+		}
+	}
+
+	txn->op = op;
+	txn->req = (struct tbuf){ .data = data->data, .len = data->len };
+	txn->n = read_u32(data);
+	if (txn->n < 0 || txn->n > namespace_count - 1)
+		box_raise(ERR_CODE_NO_SUCH_NAMESPACE, "bad namespace number");
+	txn->index = &namespace[txn->n].index[0];
+
+	if (!namespace[txn->n].enabled) {
+		say_warn("namespace %i is not enabled", txn->n);
+		box_raise(ERR_CODE_NO_SUCH_NAMESPACE, "namespace is not enabled");
+	}
+
+	txn->namespace = &namespace[txn->n];
+}
+
 void
 txn_cleanup(struct box_txn *txn)
 {
@@ -710,14 +772,33 @@ txn_commit(struct box_txn *txn)
 	if (txn->op == 0)
 		return;
 
-	say_debug("box_commit(op:%s)", messages_strs[txn->op]);
+	if (!op_is_select(txn->op)) {
+		say_debug("box_commit(op:%s)", messages_strs[txn->op]);
 
-	unlock_tuples(txn);
+		if (!txn->in_recover && txn->write_to_wal) {
+			fiber_peer_name(fiber); /* fill the cookie */
+			struct tbuf *t = tbuf_alloc(fiber->pool);
+			tbuf_append(t, &txn->op, sizeof(txn->op));
+			tbuf_append(t, txn->req.data, txn->req.len);
 
-	if (txn->op == DELETE)
-		commit_delete(txn);
+			i64 lsn = next_lsn(recovery_state, 0);
+			if (!wal_write(recovery_state, wal_tag, fiber->cookie, lsn, t))
+				box_raise(ERR_CODE_UNKNOWN_ERROR);
+			confirm_lsn(recovery_state, lsn);
+		}
+
+		unlock_tuples(txn);
+
+		if (txn->op == DELETE)
+			commit_delete(txn);
+		else
+			commit_replace(txn);
+	}
+
+	if (txn->in_recover)
+		txn_cleanup(txn);
 	else
-		commit_replace(txn);
+		fiber_register_cleanup((fiber_cleanup_handler)txn_cleanup, txn);
 }
 
 static void
@@ -725,64 +806,31 @@ txn_abort(struct box_txn *txn)
 {
 	if (txn->op == 0)
 		return;
-	say_debug("box_rollback(op:%s)", messages_strs[txn->op]);
 
-	unlock_tuples(txn);
+	fiber->iov_cnt = txn->saved_iov_cnt;
 
-	if (txn->op == DELETE)
-		return;
+	if (!op_is_select(txn->op)) {
+		say_debug("box_rollback(op:%s)", messages_strs[txn->op]);
 
-	if (txn->op == INSERT)
-		rollback_replace(txn);
-}
+		unlock_tuples(txn);
 
-static bool
-op_is_select(u32 op)
-{
-	return op == SELECT || op == SELECT_LIMIT;
+		if (txn->op == INSERT)
+			rollback_replace(txn);
+	}
+
+	txn_cleanup(txn);
 }
 
-u32
-box_dispatch(struct box_txn *txn, enum box_mode mode, u16 op,
-	     struct tbuf *data)
+static void
+box_dispach(struct box_txn *txn, struct tbuf *data)
 {
 	u32 cardinality;
-	int ret_code;
-	struct tbuf req = { .data = data->data, .len = data->len };
-	int saved_iov_cnt = fiber->iov_cnt;
-	ev_tstamp start = ev_now(), stop;
-
-	if ((ret_code = setjmp(fiber->exc)) != 0)
-		goto abort;
-
-	say_debug("box_dispatch(%i)", op);
-
-	if (!txn->in_recover) {
-		if (!op_is_select(op) && (mode == RO || !box_updates_allowed)) {
-			say_error("can't process %i command on RO port", op);
-			return ERR_CODE_NONMASTER;
-		}
-
-		fiber_register_cleanup((void *)txn_cleanup, txn);
-	}
-
-	txn->op = op;
-	txn->n = read_u32(data);
-	if (txn->n < 0 || txn->n > namespace_count - 1)
-		box_raise(ERR_CODE_NO_SUCH_NAMESPACE, "bad namespace number");
-	txn->index = &namespace[txn->n].index[0];
-
-	if (!namespace[txn->n].enabled) {
-		say_warn("namespace %i is not enabled", txn->n);
-		box_raise(ERR_CODE_NO_SUCH_NAMESPACE, "namespace is not enabled");
-	}
-
-	txn->namespace = &namespace[txn->n];
-
 	void *key;
 	u32 key_len;
 
-	switch (op) {
+	say_debug("box_dispach(%i)", txn->op);
+
+	switch (txn->op) {
 	case INSERT:
 		txn->flags = read_u32(data);
 		cardinality = read_u32(data);
@@ -790,8 +838,7 @@ box_dispatch(struct box_txn *txn, enum box_mode mode, u16 op,
 		    && namespace[txn->n].cardinality != cardinality)
 			box_raise(ERR_CODE_ILLEGAL_PARAMS,
 				  "tuple cardinality must match namespace cardinality");
-		ret_code = prepare_replace(txn, cardinality, data);
-		stat_collect(stat_base, op, 1);
+		prepare_replace(txn, cardinality, data);
 		break;
 
 	case DELETE:
@@ -803,8 +850,7 @@ box_dispatch(struct box_txn *txn, enum box_mode mode, u16 op,
 		if (data->len != 0)
 			box_raise(ERR_CODE_ILLEGAL_PARAMS, "can't unpack request");
 
-		ret_code = prepare_delete(txn, key);
-		stat_collect(stat_base, op, 1);
+		prepare_delete(txn, key);
 		break;
 
 	case SELECT:{
@@ -818,49 +864,19 @@ box_dispatch(struct box_txn *txn, enum box_mode mode, u16 op,
 			if (txn->index->key_cardinality == 0)
 				box_raise(ERR_CODE_ILLEGAL_PARAMS, "index is invalid");
 
-			stat_collect(stat_base, op, 1);
-			return process_select(txn, limit, offset, data);
+			process_select(txn, limit, offset, data);
+			break;
 		}
 
 	case UPDATE_FIELDS:
 		txn->flags = read_u32(data);
-		stat_collect(stat_base, op, 1);
-		ret_code = prepare_update_fields(txn, data);
+		prepare_update_fields(txn, data);
 		break;
 
 	default:
-		say_error("box_dispatch: unsupported command = %" PRIi32 "", op);
-		return ERR_CODE_ILLEGAL_PARAMS;
+		say_error("silverbox_dispach: unsupported command = %" PRIi32 "", txn->op);
+		box_raise(ERR_CODE_ILLEGAL_PARAMS);
 	}
-
-	if (ret_code == -1) {
-		if (!txn->in_recover) {
-			fiber_peer_name(fiber); /* fill the cookie */
-			struct tbuf *t = tbuf_alloc(fiber->pool);
-			tbuf_append(t, &op, sizeof(op));
-			tbuf_append(t, req.data, req.len);
-
-			i64 lsn = next_lsn(recovery_state, 0);
-			if (!wal_write(recovery_state, wal_tag, fiber->cookie, lsn, t)) {
-				ret_code = ERR_CODE_UNKNOWN_ERROR;
-				goto abort;
-			}
-			confirm_lsn(recovery_state, lsn);
-		}
-		txn_commit(txn);
-
-		stop = ev_now();
-		if (stop - start > cfg.too_long_threshold)
-			say_warn("too long %s: %.3f sec", messages_strs[op], stop - start);
-		return 0;
-	}
-
-	return ret_code;
-
-      abort:
-	fiber->iov_cnt = saved_iov_cnt;
-	txn_abort(txn);
-	return ret_code;
 }
 
 static int
@@ -970,75 +986,6 @@ box_snap_reader(FILE *f, struct palloc_pool *pool)
 	return convert_to_v11(row, snap_tag, default_cookie, 0);
 }
 
-static int
-snap_apply(struct box_txn *txn, struct tbuf *t)
-{
-	struct box_snap_row *row;
-
-	read_u64(t); /* drop cookie */
-
-	row = box_snap_row(t);
-	txn->n = row->namespace;
-
-	if (!namespace[txn->n].enabled) {
-		say_error("namespace %i is not configured", txn->n);
-		return -1;
-	}
-	txn->index = &namespace[txn->n].index[0];
-	assert(txn->index->key_cardinality > 0);
-
-	struct tbuf *b = palloc(fiber->pool, sizeof(*b));
-	b->data = row->data;
-	b->len = row->data_size;
-
-	if (prepare_replace(txn, row->tuple_size, b) != -1) {
-		say_error("unable prepare");
-		return -1;
-	}
-
-	txn->op = INSERT;
-	txn_commit(txn);
-	return 0;
-}
-
-static int
-wal_apply(struct box_txn *txn, struct tbuf *t)
-{
-	read_u64(t); /* drop cookie */
-
-	u16 type = read_u16(t);
-	if (box_dispatch(txn, RW, type, t) != 0)
-		return -1;
-
-	txn_cleanup(txn);
-	return 0;
-}
-
-static int
-recover_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t)
-{
-	struct box_txn *txn = txn_alloc(0);
-	int result = -1;
-	txn->in_recover = true;
-
-	/* drop wal header */
-	if (tbuf_peek(t, sizeof(struct row_v11)) == NULL)
-		return -1;
-
-	u16 tag = read_u16(t);
-	if (tag == wal_tag) {
-		result = wal_apply(txn, t);
-	} else if (tag == snap_tag) {
-		result = snap_apply(txn, t);
-	} else {
-		say_error("unknown row tag: %i", (int)tag);
-		return -1;
-	}
-
-	txn_cleanup(txn);
-	return result;
-}
-
 static int
 snap_print(struct recovery_state *r __attribute__((unused)), struct tbuf *t)
 {
@@ -1150,7 +1097,7 @@ custom_init(void)
 				else if (strcmp(cfg_key_field->type, "NUM64") == 0)
 					index->key_field[k].type = NUM64;
 				else if (strcmp(cfg_key_field->type, "STR") == 0)
-					index->key_field[k].type = STR;
+					index->key_field[k].type = STRING;
 				else
 					panic("(namespace = %" PRIu32 " index = %" PRIu32 ") "
 					      "unknown field data type: `%s'",
@@ -1208,16 +1155,104 @@ custom_init(void)
 	}
 }
 
+u32
+box_process(struct box_txn *txn, u32 op, enum box_mode mode, struct tbuf *request_data)
+{
+	ev_tstamp start = ev_now(), stop;
+
+	if (!txn->in_recover)
+		stat_collect(stat_base, txn->op, 1);
+
+	@try {
+		txn_begin(txn, mode, op, request_data);
+		box_dispach(txn, request_data);
+		txn_commit(txn);
+
+		return ERR_CODE_OK;
+	}
+	@catch (TNTPickleException *e) {
+		txn_abort(txn);
+
+		say_debug("catch exception: %s", [e Reason]);
+
+		return ERR_CODE_UNKNOWN_ERROR;
+	}
+	@catch (TNTBoxException *e) {
+		txn_abort(txn);
+
+		say_debug("catch exception: 0x%x/%s", [e Value], [e Reason]);
+
+		return [e Value];
+	}
+	@catch (id e) {
+		txn_abort(txn);
+
+		@throw;
+	}
+	@finally {
+		stop = ev_now();
+		if (!txn->in_recover &&
+		    stop - start > cfg.too_long_threshold)
+			say_warn("too long %s: %.3f sec", messages_strs[txn->op], stop - start);
+	}
+}
+
 static u32
 box_process_ro(u32 op, struct tbuf *request_data)
 {
-	return box_dispatch(txn_alloc(0), RO, op, request_data);
+	return box_process(txn_alloc(0), op, RO, request_data);
 }
 
 static u32
-box_process(u32 op, struct tbuf *request_data)
+box_process_rw(u32 op, struct tbuf *request_data)
 {
-	return box_dispatch(txn_alloc(0), RW, op, request_data);
+	return box_process(txn_alloc(0), op, RW, request_data);
+}
+
+static struct tbuf *
+convert_snap_row_to_wal(struct tbuf *t)
+{
+	struct tbuf *r = tbuf_alloc(fiber->pool);
+	struct box_snap_row *row = box_snap_row(t);
+	u16 op = INSERT;
+	u32 flags = 0;
+
+	tbuf_append(r, &op, sizeof(op));
+	tbuf_append(r, &row->namespace, sizeof(row->namespace));
+	tbuf_append(r, &flags, sizeof(flags));
+	tbuf_append(r, &row->tuple_size, sizeof(row->tuple_size));
+	tbuf_append(r, row->data, row->data_size);
+
+	return r;
+}
+
+static int
+recover_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t)
+{
+	struct box_txn *txn = txn_alloc(0);
+	u16 op;
+
+	txn->in_recover = true;
+
+	/* drop wal header */
+	if (tbuf_peek(t, sizeof(struct row_v11)) == NULL)
+		return -1;
+
+	u16 tag = read_u16(t);
+	read_u64(t); /* drop cookie */
+	if (tag == snap_tag)
+		t = convert_snap_row_to_wal(t);
+	else if (tag != wal_tag) {
+		say_error("unknown row tag: %i", (int)tag);
+		return -1;
+	}
+
+	op = read_u16(t);
+
+	if (box_process(txn, op, RW, t) != ERR_CODE_OK)
+		return -1;
+
+	return 0;
 }
 
 static void
@@ -1389,7 +1424,7 @@ mod_init(void)
 				     box_process_ro, NULL);
 
 		if (cfg.primary_port != 0)
-			fiber_server(tcp_server, cfg.primary_port, iproto_interact, box_process,
+			fiber_server(tcp_server, cfg.primary_port, iproto_interact, box_process_rw,
 				     box_bound_to_primary);
 	}
 
diff --git a/mod/box/index.h b/mod/box/index.h
index 7c259d6e69..7a0a2d15c0 100644
--- a/mod/box/index.h
+++ b/mod/box/index.h
@@ -49,7 +49,7 @@ struct field {
 	};
 };
 
-enum field_data_type { NUM, NUM64, STR };
+enum field_data_type { NUM, NUM64, STRING };
 
 struct tree_index_member {
 	struct box_tuple *tuple;
diff --git a/mod/box/index.c b/mod/box/index.m
similarity index 99%
rename from mod/box/index.c
rename to mod/box/index.m
index 8c7a54aecb..9f235cbe3c 100644
--- a/mod/box/index.c
+++ b/mod/box/index.m
@@ -80,7 +80,7 @@ field_compare(struct field *f1, struct field *f2, enum field_data_type type)
 		assert(f1->len == sizeof(f1->u64));
 
 		return f1->u64 >f2->u64 ? 1 : f1->u64 == f2->u64 ? 0 : -1;
-	} else if (type == STR) {
+	} else if (type == STRING) {
 		i32 cmp;
 		void *f1_data, *f2_data;
 
@@ -451,7 +451,7 @@ validate_indeces(struct box_txn *txn)
 	if (namespace[txn->n].index[1].key_cardinality != 0) {	/* there is more then one index */
 		foreach_index(txn->n, index) {
 			for (u32 f = 0; f < index->key_cardinality; ++f) {
-				if (index->key_field[f].type == STR)
+				if (index->key_field[f].type == STRING)
 					continue;
 
 				void *field = tuple_field(txn->tuple, index->key_field[f].fieldno);
diff --git a/mod/box/memcached.c b/mod/box/memcached.m
similarity index 99%
rename from mod/box/memcached.c
rename to mod/box/memcached.m
index be8efa19f3..06a842f67f 100644
--- a/mod/box/memcached.c
+++ b/mod/box/memcached.m
@@ -120,7 +120,7 @@ store(struct box_txn *txn, void *key, u32 exptime, u32 flags, u32 bytes, u8 *dat
 	int key_len = load_varint32(&key);
 	say_debug("memcached/store key:(%i)'%.*s' exptime:%"PRIu32" flags:%"PRIu32" cas:%"PRIu64,
 		  key_len, key_len, (u8 *)key, exptime, flags, cas);
-	return box_dispatch(txn, RW, INSERT, req); /* FIXME: handle RW/RO */
+	return box_process(txn, RW, INSERT, req); /* FIXME: handle RW/RO */
 }
 
 static int
@@ -133,7 +133,7 @@ delete(struct box_txn *txn, void *key)
 	tbuf_append(req, &key_len, sizeof(key_len));
 	tbuf_append_field(req, key);
 
-	return box_dispatch(txn, RW, DELETE, req);
+	return box_process(txn, RW, DELETE, req);
 }
 
 static struct box_tuple *
diff --git a/mod/box/memcached.rl b/mod/box/memcached.rl
index a7e0259d93..219a6e832d 100644
--- a/mod/box/memcached.rl
+++ b/mod/box/memcached.rl
@@ -111,7 +111,7 @@ store(struct box_txn *txn, void *key, u32 exptime, u32 flags, u32 bytes, u8 *dat
 	int key_len = load_varint32(&key);
 	say_debug("memcached/store key:(%i)'%.*s' exptime:%"PRIu32" flags:%"PRIu32" cas:%"PRIu64,
 		  key_len, key_len, (u8 *)key, exptime, flags, cas);
-	return box_dispatch(txn, RW, INSERT, req); /* FIXME: handle RW/RO */
+	return box_process(txn, RW, INSERT, req); /* FIXME: handle RW/RO */
 }
 
 static int
@@ -124,7 +124,7 @@ delete(struct box_txn *txn, void *key)
 	tbuf_append(req, &key_len, sizeof(key_len));
 	tbuf_append_field(req, key);
 
-	return box_dispatch(txn, RW, DELETE, req);
+	return box_process(txn, RW, DELETE, req);
 }
 
 static struct box_tuple *
diff --git a/mod/feeder/CMakeLists.txt b/mod/feeder/CMakeLists.txt
index 8e7914935c..4852343fe7 100644
--- a/mod/feeder/CMakeLists.txt
+++ b/mod/feeder/CMakeLists.txt
@@ -1 +1 @@
-tarantool_module("feeder" feeder.c)
+tarantool_module("feeder" feeder.m)
diff --git a/mod/feeder/feeder.c b/mod/feeder/feeder.m
similarity index 100%
rename from mod/feeder/feeder.c
rename to mod/feeder/feeder.m
-- 
GitLab