diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee9f9944fc2f4c9dcca9f84c4243ce7191daadd7..29228c13c80d5cb86e46876c1ebd612c47664d63 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 a13e8e02540feda16194ec07ccc73e4a49a62d2a..cd5fc2e574324ba7504aae1ecb605647ef081455 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 cc4ef3a14f97dd2cb703b62609e3f2254046fd89..6f930b537c5f8981d0e3cf9913e0c664a239a608 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 7218b9624ba74692d90c4e32d6e57a10351b9d05..deea2030808b49a6f11e48e380d5c8dd2a17ba8c 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 6719ca8a8ebf5fb81de928a61f72a5b5bff39495..654730105b994c4489d404c6b33bc4c3e85025e3 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 0075f778e70c4424b824c31fa5ff1c5ebab36994..c3887e92ed848d8942b8914a77a70d9fab3bb063 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 3898f7798739f59864479accab44b095540497a5..58792abe3ae53dc9bbfc967f4b0d7a6eccd162c8 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 9ccc809a0fcd1d034ebeb8e1756d082a754b16fe..1c59e887b9d64755b3c276fde330a97f1f7070fb 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 7a6e6a2445632236b1a7bc584b6f7d4f69532298..3266ae52a02a94a948749d66f4f810d816ccd2b8 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 0000000000000000000000000000000000000000..45eaacf81be1c05ccd508cb8ff2dde3b8898f864
--- /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 690f4f75570e700d8d439e9995c97cd909107a4a..b0645334f766135561abcda43139aa5e1567d9a8 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 345c8e94c41873366de40e76b83fad421d425a8b..00d3f9f5c666349d1b1319c67ed4185b1bb5c794 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 7201582979442c16a6e1ffdb92b19f8ab4ecbe1d..db02df43c00966083aaf7cfa76309caccd628e06 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 013c5fe6baaacdc2938ef187fb4d21a4f12132d2..5185e32e3371abdc2fb35063e4fa7814d0fbba12 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 1450e582ad42422ee48f0cf56acce54bbf7ed683..d14b975cd5ef172bc70021bd6d7d530ae913b9db 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 0000000000000000000000000000000000000000..d872055316bf07c5c86ba1517ad313edf4209932
--- /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 42871d625199bb8fd56475e00958e8d009cb423b..191bdd8d1221863cd1f21ced3c38eda32e5c34be 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 8a51cde6729449e62e3dcb03da258b8bbf4652cf..9fb718b5c604f5aca694d3a484c63c25ca87ec78 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 cc839a8eacd5150b63d4f04e10dd754e81a20b66..60cdf4032daf07780508ae0cbca64fd05726349d 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 f92e265ecd4c66fdd11a6faccef7369f04c9b042..7d0af32b5d05a4b0e4cf82b52fac50e8a111e210 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 ba2a470b58f600e91362a5c49eb196c32f4d1227..5a3de9b17ef333967e6c678dd9b6ebac0c566565 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 d501e85b5d5fd9c5d773991d077c69aa98a4bf1d..2eb6a46ccdca719413ba07e21404ca287294e955 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 7c259d6e69186baef9f5841193dd9bbd27880ac8..7a0a2d15c0cec3eb02a1fbee4c26d6afc1b77069 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 8c7a54aecb68b265acfa53eb822db470cd32003c..9f235cbe3c9b3bec852eccb969e8214b0897e1a2 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 be8efa19f384b5a7c67cdc049f7b169950a73700..06a842f67f0ec7b52dd5e52c21a47c2e83cda229 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 a7e0259d934d61cbbc15e61fb72924975f50385a..219a6e832dff1c02d3c83a9c5dca08213b6f244d 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 8e7914935cc32239ce779250be3cfeaf9589b70c..4852343fe75f602983ae07dca3c1f6329c7346c9 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