diff --git a/src/admin.cc b/src/admin.cc index 026bbbc06f062fe4c731314e7f74f52a301e06c9..5cf23311281b0170a6acca7c67e6229f9248203f 100644 --- a/src/admin.cc +++ b/src/admin.cc @@ -100,21 +100,14 @@ admin_handler(va_list ap) struct iobuf *iobuf = va_arg(ap, struct iobuf *); lua_State *L = lua_newthread(tarantool_L); LuarefGuard coro_guard(tarantool_L); - /* - * Admin and iproto connections must have a - * session object, representing the state of - * a remote client: it's used in Lua - * stored procedures. - */ - SessionGuard sesion_guard(coio.fd, *(uint64_t *) addr); + /* Session stores authentication and transaction state. */ + SessionGuardWithTriggers sesion_guard(coio.fd, *(uint64_t *) addr); auto scoped_guard = make_scoped_guard([&] { evio_close(loop(), &coio); iobuf_delete(iobuf); }); - trigger_run(&session_on_connect, NULL); - for (;;) { if (admin_dispatch(&coio, iobuf, L) < 0) return; diff --git a/src/box/box.cc b/src/box/box.cc index 9c3dcad5849a9a64b46b1363d4a51206e373e100..ef048d4a7cf8abe98d1e4d3f5599bc20ec873752 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -73,27 +73,15 @@ struct request_replace_body { uint8_t k_tuple; } __attribute__((packed)); -void -port_send_tuple(struct port *port, struct txn *txn) -{ - struct tuple *tuple; - if ((tuple = txn->new_tuple) || (tuple = txn->old_tuple)) - port_add_tuple(port, tuple); -} - static void process_rw(struct port *port, struct request *request) { - struct txn *txn = txn_begin(); try { stat_collect(stat_base, request->type, 1); - request->execute(request, txn, port); - txn_commit(txn); - port_send_tuple(port, txn); + request->execute(request, port); port_eof(port); - txn_finish(txn); } catch (Exception *e) { - txn_rollback(txn); + txn_rollback(); throw; } } diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc index 2eb52794cf0ff21cabfb774130d36d7adf9c99b8..2566692685b4cc765a8b13321f01b78bb6cfc285 100644 --- a/src/box/lua/call.cc +++ b/src/box/lua/call.cc @@ -89,19 +89,15 @@ port_lua_add_tuple(struct port *port, struct tuple *tuple) } } - -static struct port * -port_lua_create(struct lua_State *L) +void +port_lua_create(struct port_lua *port, struct lua_State *L) { static struct port_vtab port_lua_vtab = { port_lua_add_tuple, null_port_eof, }; - struct port_lua *port = (struct port_lua *) - region_alloc(&fiber()->gc, sizeof(struct port_lua)); port->vtab = &port_lua_vtab; port->L = L; - return (struct port *) port; } static void @@ -219,32 +215,21 @@ lbox_process(lua_State *L) */ return luaL_error(L, "box.process(CALL, ...) is not allowed"); } - size_t allocated_size = region_used(&fiber()->gc); + /* Capture all output into a Lua table. */ struct port *port_lua = port_lua_table_create(L); - try { - struct request request; - request_create(&request, op); - request_decode(&request, req, sz); - box_process(port_lua, &request); + struct request request; + request_create(&request, op); + request_decode(&request, req, sz); + box_process(port_lua, &request); - /* - * This only works as long as port_lua doesn't - * use fiber->cleanup and fiber->gc. - */ - region_truncate(&fiber()->gc, allocated_size); - } catch (Exception *e) { - region_truncate(&fiber()->gc, allocated_size); - throw; - } return 1; } -static struct request * -lbox_request_create(struct lua_State *L, enum iproto_request_type type, +void +lbox_request_create(struct request *request, + struct lua_State *L, enum iproto_request_type type, int key, int tuple) { - struct request *request = (struct request *) - region_alloc(&fiber()->gc, sizeof(struct request)); request_create(request, type); request->space_id = lua_tointeger(L, 1); if (key > 0) { @@ -263,7 +248,6 @@ lbox_request_create(struct lua_State *L, enum iproto_request_type type, if (mp_typeof(*request->tuple) != MP_ARRAY) tnt_raise(ClientError, ER_TUPLE_NOT_ARRAY); } - return request; } static void @@ -331,10 +315,11 @@ lbox_insert(lua_State *L) if (lua_gettop(L) != 2 || !lua_isnumber(L, 1)) return luaL_error(L, "Usage space:insert(tuple)"); - RegionGuard region_guard(&fiber()->gc); - struct request *request = lbox_request_create(L, IPROTO_INSERT, - -1, 2); - box_process(port_lua_create(L), request); + struct request request; + struct port_lua port; + lbox_request_create(&request, L, IPROTO_INSERT, -1, 2); + port_lua_create(&port, L); + box_process((struct port *) &port, &request); return lua_gettop(L) - 2; } @@ -344,10 +329,11 @@ lbox_replace(lua_State *L) if (lua_gettop(L) != 2 || !lua_isnumber(L, 1)) return luaL_error(L, "Usage space:replace(tuple)"); - RegionGuard region_guard(&fiber()->gc); - struct request *request = lbox_request_create(L, IPROTO_REPLACE, - -1, 2); - box_process(port_lua_create(L), request); + struct request request; + struct port_lua port; + lbox_request_create(&request, L, IPROTO_REPLACE, -1, 2); + port_lua_create(&port, L); + box_process((struct port *) &port, &request); return lua_gettop(L) - 2; } @@ -357,12 +343,13 @@ lbox_update(lua_State *L) if (lua_gettop(L) != 4 || !lua_isnumber(L, 1) || !lua_isnumber(L, 2)) return luaL_error(L, "Usage space:update(key, ops)"); - RegionGuard region_guard(&fiber()->gc); - struct request *request = lbox_request_create(L, IPROTO_UPDATE, - 3, 4); - request->field_base = 1; /* field ids are one-indexed */ + struct request request; + struct port_lua port; + lbox_request_create(&request, L, IPROTO_UPDATE, 3, 4); + request.field_base = 1; /* field ids are one-indexed */ + port_lua_create(&port, L); /* Ignore index_id for now */ - box_process(port_lua_create(L), request); + box_process((struct port *) &port, &request); return lua_gettop(L) - 4; } @@ -372,11 +359,12 @@ lbox_delete(lua_State *L) if (lua_gettop(L) != 3 || !lua_isnumber(L, 1) || !lua_isnumber(L, 2)) return luaL_error(L, "Usage space:delete(key)"); - RegionGuard region_guard(&fiber()->gc); - struct request *request = lbox_request_create(L, IPROTO_DELETE, - 3, -1); + struct request request; + struct port_lua port; + lbox_request_create(&request, L, IPROTO_DELETE, 3, -1); + port_lua_create(&port, L); /* Ignore index_id for now */ - box_process(port_lua_create(L), request); + box_process((struct port *) &port, &request); return lua_gettop(L) - 3; } @@ -503,10 +491,9 @@ access_check_func(const char *name, uint32_t name_len, * (implementation of 'CALL' command code). */ void -box_lua_call(struct request *request, struct txn *txn, struct port *port) +box_lua_call(struct request *request, struct port *port) { struct user *user = user(); - (void) txn; lua_State *L = lua_newthread(tarantool_L); LuarefGuard coro_ref(tarantool_L); const char *name = request->key; diff --git a/src/box/lua/call.h b/src/box/lua/call.h index c5ad2c4bab7ff20b10ecb65db2ff0e6302b753c1..44ea45bd4a9abb987d4bdf666748ac8479dac0d6 100644 --- a/src/box/lua/call.h +++ b/src/box/lua/call.h @@ -31,7 +31,6 @@ #include <stdint.h> -struct txn; struct request; struct port; @@ -40,7 +39,7 @@ struct port; * (implementation of 'CALL' command code). */ void -box_lua_call(struct request *request, struct txn *txn, struct port *port); +box_lua_call(struct request *request, struct port *port); extern "C" { struct port_ffi diff --git a/src/box/recovery.cc b/src/box/recovery.cc index 70b2990f21f272b714ea3445f6a5c98c9673a07c..25074974cd7cabec671895f18429c5afd0d6e4be 100644 --- a/src/box/recovery.cc +++ b/src/box/recovery.cc @@ -47,6 +47,7 @@ #include "scoped_guard.h" #include "box/cluster.h" #include "vclock.h" +#include "session.h" /* * Recovery subsystem @@ -531,6 +532,7 @@ recovery_finalize(struct recovery_state *r) * locally or send to the replica. */ struct wal_watcher { + struct session *session; /** * Rescan the WAL directory in search for new WAL files * every wal_dir_rescan_delay seconds. @@ -572,7 +574,10 @@ recovery_rescan_dir(ev_loop * loop, ev_timer *w, int /* revents */) struct wal_watcher *watcher = r->watcher; struct log_io *save_current_wal = r->current_wal; + /** To process transactions, we need a working session. */ + fiber_set_session(fiber(), r->watcher->session); int result = recover_remaining_wals(r); + fiber_set_session(fiber(), NULL); if (result < 0) panic("recover failed: %i", result); if (save_current_wal != r->current_wal) { @@ -588,7 +593,9 @@ recovery_rescan_file(ev_loop * loop, ev_stat *w, int /* revents */) { struct recovery_state *r = (struct recovery_state *) w->data; struct wal_watcher *watcher = r->watcher; + fiber_set_session(fiber(), r->watcher->session); int result = recover_wal(r, r->current_wal); + fiber_set_session(fiber(), NULL); if (result < 0) panic("recover failed"); if (result == LOG_EOF) { @@ -609,6 +616,8 @@ recovery_follow_local(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay) struct wal_watcher *watcher = r->watcher= &wal_watcher; + r->watcher->session = session_create(-1, 0); + ev_timer_init(&watcher->dir_timer, recovery_rescan_dir, wal_dir_rescan_delay, wal_dir_rescan_delay); watcher->dir_timer.data = watcher->stat.data = r; @@ -629,6 +638,8 @@ recovery_stop_local(struct recovery_state *r) ev_timer_stop(loop(), &watcher->dir_timer); if (ev_is_active(&watcher->stat)) ev_stat_stop(loop(), &watcher->stat); + session_destroy(watcher->session); + watcher->session = NULL; r->watcher = NULL; } diff --git a/src/box/request.cc b/src/box/request.cc index 759f3bbb754102825374f882da6f42aa5b1fd0b2..5c8deca376917dcd866752c308105ce077d971cc 100644 --- a/src/box/request.cc +++ b/src/box/request.cc @@ -41,38 +41,6 @@ #include "authentication.h" #include "access.h" -#if 0 -static const char * -read_tuple(const char **reqpos, const char *reqend) -{ - const char *tuple = *reqpos; - if (unlikely(mp_check(reqpos, reqend))) { - say_error("\n" - "********************************************\n" - "* Found a corrupted tuple in a request! *\n" - "* This can be either due to a memory *\n" - "* corruption or a bug in the server. *\n" - "* The tuple can not be loaded. *\n" - "********************************************\n" - "Request tail, BASE64 encoded: \n"); - - uint32_t tuple_len = reqend - tuple; - int base64_buflen = base64_bufsize(tuple_len); - char *base64_buf = (char *) malloc(base64_buflen); - int len = base64_encode(tuple, tuple_len, - base64_buf, base64_buflen); - write(STDERR_FILENO, base64_buf, len); - free(base64_buf); - tnt_raise(ClientError, ER_INVALID_MSGPACK, "tuple"); - } - - if (unlikely(mp_typeof(*tuple) != MP_ARRAY)) - tnt_raise(ClientError, ER_TUPLE_NOT_ARRAY); - - return tuple; -} -#endif - enum dup_replace_mode dup_replace_mode(uint32_t op) { @@ -80,9 +48,9 @@ dup_replace_mode(uint32_t op) } static void -execute_replace(struct request *request, struct txn *txn, struct port *port) +execute_replace(struct request *request, struct port *port) { - (void) port; + struct txn *txn = txn_begin(); struct space *space = space_cache_find(request->space_id); space_check_access(space, PRIV_W); @@ -94,13 +62,13 @@ execute_replace(struct request *request, struct txn *txn, struct port *port) txn_add_redo(txn, request); txn_replace(txn, space, NULL, new_tuple, mode); + txn_commit(txn, port); } static void -execute_update(struct request *request, struct txn *txn, - struct port *port) +execute_update(struct request *request, struct port *port) { - (void) port; + struct txn *txn = txn_begin(); /* Parse UPDATE request. */ /** Search key and key part count. */ @@ -115,8 +83,10 @@ execute_update(struct request *request, struct txn *txn, struct tuple *old_tuple = pk->findByKey(key, part_count); txn_add_redo(txn, request); - if (old_tuple == NULL) + if (old_tuple == NULL) { + txn_commit(txn, port); return; + } /* Update the tuple. */ struct tuple *new_tuple = tuple_update(space->format, @@ -128,11 +98,13 @@ execute_update(struct request *request, struct txn *txn, TupleGuard guard(new_tuple); space_validate_tuple(space, new_tuple); txn_replace(txn, space, old_tuple, new_tuple, DUP_INSERT); + txn_commit(txn, port); } static void -execute_delete(struct request *request, struct txn *txn, struct port *port) +execute_delete(struct request *request, struct port *port) { + struct txn *txn = txn_begin(); (void) port; struct space *space = space_cache_find(request->space_id); space_check_access(space, PRIV_W); @@ -145,16 +117,16 @@ execute_delete(struct request *request, struct txn *txn, struct port *port) struct tuple *old_tuple = pk->findByKey(key, part_count); txn_add_redo(txn, request); - if (old_tuple == NULL) - return; - txn_replace(txn, space, old_tuple, NULL, DUP_REPLACE_OR_INSERT); + if (old_tuple != NULL) + txn_replace(txn, space, old_tuple, NULL, DUP_REPLACE_OR_INSERT); + txn_commit(txn, port); } static void -execute_select(struct request *request, struct txn *txn, struct port *port) +execute_select(struct request *request, struct port *port) { - (void) txn; + struct txn *txn = txn_begin(); struct space *space = space_cache_find(request->space_id); space_check_access(space, PRIV_R); Index *index = index_find(space, request->index_id); @@ -187,11 +159,11 @@ execute_select(struct request *request, struct txn *txn, struct port *port) break; port_add_tuple(port, tuple); } + txn_commit(txn, port); } void -execute_auth(struct request *request, struct txn * /* txn */, - struct port * /* port */) +execute_auth(struct request *request, struct port * /* port */) { const char *user = request->key; uint32_t len = mp_decode_strl(&user); diff --git a/src/box/request.h b/src/box/request.h index 6a188098f70710a83187df2371265f688cb618ff..a6d2dc8426a05fd11d2a8b0cea0ef487910f3711 100644 --- a/src/box/request.h +++ b/src/box/request.h @@ -34,7 +34,7 @@ struct txn; struct port; -typedef void (*request_execute_f)(struct request *, struct txn *, struct port *); +typedef void (*request_execute_f)(struct request *, struct port *); enum { REQUEST_IOVMAX = IPROTO_PACKET_BODY_IOVMAX }; struct request diff --git a/src/box/txn.cc b/src/box/txn.cc index 6ab21cae40818f40648126be35a4fcedc4838d68..52ab7b7a421519b7ecdb00597eeeb7ccde3157d0 100644 --- a/src/box/txn.cc +++ b/src/box/txn.cc @@ -34,9 +34,20 @@ #include "recovery.h" #include <fiber.h> #include "request.h" /* for request_name */ +#include "session.h" +#include "port.h" double too_long_threshold; +void +port_send_tuple(struct port *port, struct txn *txn) +{ + struct tuple *tuple; + if ((tuple = txn->new_tuple) || (tuple = txn->old_tuple)) + port_add_tuple(port, tuple); +} + + void txn_add_redo(struct txn *txn, struct request *request) { @@ -80,16 +91,39 @@ txn_replace(struct txn *txn, struct space *space, struct txn * txn_begin() { + assert(! in_txn()); struct txn *txn = (struct txn *) region_alloc0(&fiber()->gc, sizeof(*txn)); rlist_create(&txn->on_commit); rlist_create(&txn->on_rollback); + in_txn() = txn; return txn; } +/** + * txn_finish() follows txn_commit() on success. + * It's moved to a separate call to be able to send + * old tuple to the user before it's deleted. + */ void -txn_commit(struct txn *txn) +txn_finish(struct txn *txn) { + assert(txn == in_txn()); + if (txn->old_tuple) + tuple_ref(txn->old_tuple, -1); + if (txn->space) + txn->space->engine->factory->txnFinish(txn); + TRASH(txn); + /** Free volatile txn memory. */ + fiber_gc(); + in_txn() = NULL; +} + + +void +txn_commit(struct txn *txn, struct port *port) +{ + assert(txn == in_txn()); if ((txn->old_tuple || txn->new_tuple) && !space_is_temporary(txn->space)) { int res = 0; @@ -110,26 +144,16 @@ txn_commit(struct txn *txn) tnt_raise(LoggedError, ER_WAL_IO); } trigger_run(&txn->on_commit, txn); /* must not throw. */ -} - -/** - * txn_finish() follows txn_commit() on success. - * It's moved to a separate call to be able to send - * old tuple to the user before it's deleted. - */ -void -txn_finish(struct txn *txn) -{ - if (txn->old_tuple) - tuple_ref(txn->old_tuple, -1); - if (txn->space) - txn->space->engine->factory->txnFinish(txn); - TRASH(txn); + port_send_tuple(port, txn); + txn_finish(txn); } void -txn_rollback(struct txn *txn) +txn_rollback() { + struct txn *txn = in_txn(); + if (txn == NULL) + return; if (txn->old_tuple || txn->new_tuple) { space_replace(txn->space, txn->new_tuple, txn->old_tuple, DUP_INSERT); @@ -138,4 +162,7 @@ txn_rollback(struct txn *txn) tuple_ref(txn->new_tuple, -1); } TRASH(txn); + /** Free volatile txn memory. */ + fiber_gc(); + in_txn() = NULL; } diff --git a/src/box/txn.h b/src/box/txn.h index e46b085fd202cec67698079fe578817b564697ce..73a4db31f05a6227e919b25ecf70f5bcd4f5ed9b 100644 --- a/src/box/txn.h +++ b/src/box/txn.h @@ -48,10 +48,14 @@ struct txn { struct iproto_header *row; }; +/* pointer to the current multithreaded transaction (if any) */ +#define in_txn() (fiber()->session->txn) + struct txn *txn_begin(); -void txn_commit(struct txn *txn); +void txn_commit(struct txn *txn, struct port *port); void txn_finish(struct txn *txn); -void txn_rollback(struct txn *txn); +void txn_rollback(); + void txn_replace(struct txn *txn, struct space *space, struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode); diff --git a/src/iproto.cc b/src/iproto.cc index ad52bc05ada65fe67fee61ab860347d227567581..1ac623a71ca0343364282f08ceb782960ce026db 100644 --- a/src/iproto.cc +++ b/src/iproto.cc @@ -212,7 +212,6 @@ iproto_queue_handler(va_list ap) request->process(request); } /** Put the current fiber into a queue fiber cache. */ - fiber_gc(); rlist_add_entry(&i_queue->fiber_cache, fiber(), state); fiber_yield(); goto restart; @@ -345,7 +344,10 @@ iproto_connection_delete(struct iproto_connection *con) { assert(iproto_connection_is_idle(con)); assert(!evio_is_active(&con->output)); - session_destroy(con->session); /* Never throws. No-op if sid is 0. */ + if (con->session) { + session_run_on_disconnect_triggers(con->session); + session_destroy(con->session); + } iobuf_delete(con->iobuf[0]); iobuf_delete(con->iobuf[1]); if (con->disconnect) @@ -772,7 +774,9 @@ iproto_process_connect(struct iproto_request *request) con->session = session_create(fd, con->cookie); coio_write(&con->input, iproto_greeting(con->session->salt), IPROTO_GREETING_SIZE); - trigger_run(&session_on_connect, NULL); + session_run_on_connect_triggers(con->session); + /* Set session user to guest, until it is authenticated. */ + session_set_user(con->session, GUEST, GUEST); } catch (ClientError *e) { iproto_reply_error(&iobuf->out, e, request->header.type); try { diff --git a/src/lib/small/mempool.h b/src/lib/small/mempool.h index 03e10b807f02b21e6f82cba3b4a873cb4b61a64a..55fa00a0c319e57df3044c9252518a0df521dbbe 100644 --- a/src/lib/small/mempool.h +++ b/src/lib/small/mempool.h @@ -31,6 +31,7 @@ #include <stddef.h> #include <stdbool.h> #include <inttypes.h> +#include <string.h> #include "small/slab_cache.h" #define RB_COMPACT 1 #include "third_party/rb.h" @@ -247,6 +248,9 @@ mslab_free(struct mempool *pool, struct mslab *slab, void *ptr); static inline void mempool_free(struct mempool *pool, void *ptr) { +#ifndef NDEBUG + memset(ptr, '#', pool->objsize); +#endif struct mslab *slab = (struct mslab *) slab_from_ptr(pool->cache, ptr, pool->slab_order); pool->slabs.stats.used -= pool->objsize; diff --git a/src/lua/init.cc b/src/lua/init.cc index 85e57d201d2f1dea042c632776ecf6f3d556ad79..8ebca87f4505a1cc93cd4d6315ee9c18cc2abff3 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -411,11 +411,6 @@ run_script(va_list ap) /* clear the stack from return values. */ lua_settop(L, 0); - /* - * The file doesn't exist. It's OK, tarantool may - * have no init file. - */ - /* * Lua script finished. Stop the auxiliary event loop and * return control back to tarantool_lua_run_script. diff --git a/src/session.cc b/src/session.cc index 41d9b78be5d3670dcee40fb16866a3bf15535a96..2151f4c808c8beaef7e85f98356d43ea9be2795c 100644 --- a/src/session.cc +++ b/src/session.cc @@ -63,11 +63,6 @@ session_create(int fd, uint64_t cookie) session->cookie = cookie; session->delim[0] = '\0'; session->txn = NULL; - - /* - * At first the session user is a superuser, - * to make sure triggers run correctly. - */ session_set_user(session, ADMIN, ADMIN); random_bytes(session->salt, SESSION_SEED_SIZE); struct mh_i32ptr_node_t node; @@ -81,23 +76,12 @@ session_create(int fd, uint64_t cookie) tnt_raise(ClientError, ER_MEMORY_ISSUE, "session hash", "new session"); } - /* - * Run the trigger *after* setting the current - * fiber sid. - */ - fiber_set_session(fiber(), session); - - /* Set session user to guest, until it is authenticated. */ - session_set_user(session, GUEST, GUEST); return session; } void -session_destroy(struct session *session) +session_run_on_disconnect_triggers(struct session *session) { - if (session == NULL) /* no-op for a dead session. */ - return; - fiber_set_session(fiber(), session); /* For triggers. */ session_set_user(session, ADMIN, ADMIN); try { @@ -108,6 +92,17 @@ session_destroy(struct session *session) /* catch all. */ } session_storage_cleanup(session->id); +} + +void +session_run_on_connect_triggers(struct session *session) +{ + trigger_run(&session_on_connect, NULL); +} + +void +session_destroy(struct session *session) +{ assert(session->txn == NULL); struct mh_i32ptr_node_t node = { session->id, NULL }; mh_i32ptr_remove(session_registry, &node, NULL); @@ -143,11 +138,23 @@ session_free() SessionGuard::SessionGuard(int fd, uint64_t cookie) { - session_set_user(session_create(fd, cookie), ADMIN, ADMIN); + session = session_create(fd, cookie); + fiber_set_session(fiber(), session); } SessionGuard::~SessionGuard() { - session_destroy(fiber()->session); + assert(session == fiber()->session); + session_destroy(session); } +SessionGuardWithTriggers::SessionGuardWithTriggers(int fd, uint64_t cookie) + :SessionGuard(fd, cookie) +{ + session_run_on_connect_triggers(session); +} + +SessionGuardWithTriggers::~SessionGuardWithTriggers() +{ + session_run_on_disconnect_triggers(session); +} diff --git a/src/session.h b/src/session.h index e15670c8179443eb718c599463fab5faad6779f0..8595c505bb5914180af23bb8f49c89e5e9135480 100644 --- a/src/session.h +++ b/src/session.h @@ -115,11 +115,20 @@ session_set_user(struct session *session, uint8_t auth_token, uint32_t uid) session->uid = uid; } -/* The global on-connect trigger. */ +/** Global on-connect triggers. */ extern struct rlist session_on_connect; -/* The global on-disconnect trigger. */ + +/** Run on-connect triggers */ +void +session_run_on_connect_triggers(struct session *session); + +/** Global on-disconnect triggers. */ extern struct rlist session_on_disconnect; +/** Run on-disconnect triggers */ +void +session_run_on_disconnect_triggers(struct session *session); + void session_init(); @@ -132,8 +141,15 @@ session_storage_cleanup(int sid); /** A helper class to create and set session in single-session fibers. */ struct SessionGuard { + struct session *session; SessionGuard(int fd, uint64_t cookie); ~SessionGuard(); }; +struct SessionGuardWithTriggers: public SessionGuard +{ + SessionGuardWithTriggers(int fd, uint64_t cookie); + ~SessionGuardWithTriggers(); +}; + #endif /* INCLUDES_TARANTOOL_SESSION_H */ diff --git a/test/box/session.storage.result b/test/box/session.storage.result index 703271f17a803e7db4f475445c7589556ac231ca..6547c6866ab67d3ba273273e63d6a95341283d06 100644 --- a/test/box/session.storage.result +++ b/test/box/session.storage.result @@ -31,7 +31,7 @@ all = getmetatable(session).aggregate_storage ... dump(all) --- -- '''[null,null,{"abc":"cde"}]''' +- '''[null,null,null,{"abc":"cde"}]''' ... --# create connection second to default --# set connection second