diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index f442df2050fc5aa2b3e9929e214fd49af74b8f92..a37523dceaf7190a287ccd3bc967eaf7f281c6b3 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -26,6 +26,7 @@ tarantool_module("box" tree_index.cc bitset_index.cc engine.cc + engine_memtx.cc space.cc alter.cc schema.cc diff --git a/src/box/alter.cc b/src/box/alter.cc index 9f8b748c990efe21e0216230c9f82188230ce217..67cb1ae033e3633e9f0eab92a4d55b67c8345b64 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -442,7 +442,9 @@ alter_space_do(struct txn *txn, struct alter_space *alter, * since engine.recover does different things depending on * the recovery phase. */ - alter->new_space->engine = alter->old_space->engine; + alter->new_space->engine->recovery = + alter->old_space->engine->recovery; + memcpy(alter->new_space->access, alter->old_space->access, sizeof(alter->old_space->access)); /* @@ -492,9 +494,12 @@ ModifySpace::prepare(struct alter_space *alter) (unsigned) space_id(alter->old_space), "can not change space engine"); + engine_recovery *recovery = + &alter->old_space->engine->recovery; + if (def.arity != 0 && def.arity != alter->old_space->def.arity && - alter->old_space->engine.state != READY_NO_KEYS && + recovery->state != READY_NO_KEYS && space_size(alter->old_space) > 0) { tnt_raise(ClientError, ER_ALTER_SPACE, @@ -502,7 +507,7 @@ ModifySpace::prepare(struct alter_space *alter) "can not change arity on a non-empty space"); } if (def.temporary != alter->old_space->def.temporary && - alter->old_space->engine.state != READY_NO_KEYS && + recovery->state != READY_NO_KEYS && space_size(alter->old_space) > 0) { tnt_raise(ClientError, ER_ALTER_SPACE, (unsigned) space_id(alter->old_space), @@ -576,7 +581,7 @@ DropIndex::alter(struct alter_space *alter) * can be put back online properly with * engine_no_keys.recover. */ - engine_derive(&alter->new_space->engine); + alter->new_space->engine->recover_derive(); } void @@ -765,7 +770,10 @@ AddIndex::alter(struct alter_space *alter) * READY_NO_KEYS is when a space has no functional keys. * Possible both during and after recovery. */ - if (alter->new_space->engine.state == READY_NO_KEYS) { + engine_recovery *recovery = + &alter->new_space->engine->recovery; + + if (recovery->state == READY_NO_KEYS) { if (new_key_def->iid == 0) { /* * Adding a primary key: bring the space @@ -777,7 +785,7 @@ AddIndex::alter(struct alter_space *alter) * key. After recovery, it means building * all keys. */ - alter->new_space->engine.recover(alter->new_space); + recovery->recover(alter->new_space); } else { /* * Adding a secondary key: nothing to do. @@ -796,8 +804,9 @@ AddIndex::alter(struct alter_space *alter) } Index *pk = index_find(alter->old_space, 0); Index *new_index = index_find(alter->new_space, new_key_def->iid); + /* READY_PRIMARY_KEY is a state that only occurs during WAL recovery. */ - if (alter->new_space->engine.state == READY_PRIMARY_KEY) { + if (recovery->state == READY_PRIMARY_KEY) { if (new_key_def->iid == 0) { /* * Bulk rebuild of the new primary key diff --git a/src/box/box.cc b/src/box/box.cc index 2074559d397744cb81e8580fe79a2eb7631cf6d0..d6fbce91a8a9eb6bd22b1ad0dd167894a2b50eee 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -47,6 +47,7 @@ extern "C" { #include "lua/call.h" #include "schema.h" #include "engine.h" +#include "engine_memtx.h" #include "space.h" #include "port.h" #include "request.h" @@ -278,6 +279,13 @@ box_free(void) stat_free(); } +static void +box_engine_init() +{ + MEMTX *memtx = new MEMTX(); + engine_register(memtx); +} + void box_init() { @@ -287,7 +295,7 @@ box_init() tuple_init(cfg.slab_alloc_arena, cfg.slab_alloc_minimal, cfg.slab_alloc_factor); - engine_register(&engine_memtx); + box_engine_init(); schema_init(); user_cache_init(); diff --git a/src/box/engine.cc b/src/box/engine.cc index b389267a21ff1aae15dee69222a21febef9e7b1a..e393cde49598ba703783c9214d88e204194ff8a8 100644 --- a/src/box/engine.cc +++ b/src/box/engine.cc @@ -34,19 +34,40 @@ #include <stdlib.h> #include <string.h> -RLIST_HEAD(engines); +static RLIST_HEAD(engines); -/** Register engine instance. */ -void engine_register(struct engine *engine) +EngineFactory::EngineFactory(const char *engine_name) + :name(engine_name), + link(RLIST_INITIALIZER(link)) +{} + +void EngineFactory::init() +{} + +void EngineFactory::shutdown() +{} + +void EngineFactory::close(Engine*) +{} + +Engine::Engine(EngineFactory *f) + :host(f) +{ + /* derive recovery state from engine factory */ + recover_derive(); +} + +/** Register engine factory instance. */ +void engine_register(EngineFactory *engine) { rlist_add_entry(&engines, engine, link); } -/** Find engine by name. */ -struct engine* +/** Find factory engine by name. */ +EngineFactory* engine_find(const char *name) { - struct engine *e; + EngineFactory *e; rlist_foreach_entry(e, &engines, link) { if (strcmp(e->name, name) == 0) return e; @@ -54,70 +75,21 @@ engine_find(const char *name) tnt_raise(LoggedError, ER_NO_SUCH_ENGINE, name); } -/** Init engine instance. */ -void engine_init(struct engine *instance, const char *name) -{ - struct engine *origin = engine_find(name); - *instance = *origin; - instance->origin = origin; - instance->link = RLIST_INITIALIZER(instance->link); - instance->init(instance); -} - -/** Shutdown all engines. */ -void engine_shutdown() -{ - struct engine *e; - rlist_foreach_entry(e, &engines, link) - e->free(e); -} - /** Call a visitor function on every registered engine. */ -void engine_foreach(void (*func)(struct engine *engine, void *udata), void *udata) +void engine_foreach(void (*func)(EngineFactory *engine, void *udata), + void *udata) { - struct engine *e; + EngineFactory *e; rlist_foreach_entry(e, &engines, link) func(e, udata); } -/** - * Derive recovery state from a parent engine - * handler. - */ -void engine_derive(struct engine *engine) +/** Shutdown all engine factories. */ +void engine_shutdown() { - engine->state = engine->origin->state; - engine->recover = engine->origin->recover; - engine->replace = engine->origin->replace; + EngineFactory *e, *tmp; + rlist_foreach_entry_safe(e, &engines, link, tmp) { + e->shutdown(); + delete e; + } } - -static inline void -memtx_init(struct engine *engine __attribute((unused))) -{ } - -static inline void -memtx_free(struct engine *engine __attribute((unused))) -{ } - -/** - * This is a vtab with which a newly created space which has no - * keys is primed. - * At first it is set to correctly work for spaces created during - * recovery from snapshot. In process of recovery it is updated as - * below: - * - * 1) after SNAP is loaded: - * recover = space_build_primary_key - * 2) when all XLOGs are loaded: - * recover = space_build_all_keys - */ -struct engine engine_memtx = { - .name = "memtx", - .origin = NULL, - .state = READY_NO_KEYS, - .recover = space_begin_build_primary_key, - .replace = space_replace_no_keys, - .init = memtx_init, - .free = memtx_free, - .link = RLIST_INITIALIZER(engine_memtx.link) -}; diff --git a/src/box/engine.h b/src/box/engine.h index 24ada8d662c74fe8e23743f46a9257ffa93bd815..11bccdeab9fb0224834d398cfdb0ba0f8722c378 100644 --- a/src/box/engine.h +++ b/src/box/engine.h @@ -32,15 +32,8 @@ #include "index.h" #include <exception.h> -struct tuple; struct space; - -typedef void (*engine_recover_f)(struct space *space); - -typedef struct tuple* -(*engine_replace_f)(struct space *space, - struct tuple *old_tuple, - struct tuple *new_tuple, enum dup_replace_mode); +struct tuple; /** Reflects what space_replace() is supposed to do. */ enum engine_recovery_state { @@ -66,9 +59,13 @@ enum engine_recovery_state { READY_ALL_KEYS }; -struct engine { - const char *name; - struct engine *origin; +typedef void (*engine_recover_f)(struct space*); + +typedef struct tuple* +(*engine_replace_f)(struct space*, struct tuple*, struct tuple*, + enum dup_replace_mode); + +struct engine_recovery { enum engine_recovery_state state; /* Recover is called after each recover step to enable * keys. When recovery is complete, it enables all keys @@ -76,37 +73,59 @@ struct engine { */ engine_recover_f recover; engine_replace_f replace; +}; - void (*init)(struct engine*); - void (*free)(struct engine*); +struct Engine; +/** Engine instance */ +struct EngineFactory: public Object { + EngineFactory(const char *engine_name); + virtual ~EngineFactory() {} + virtual void init(); + virtual void shutdown(); + virtual Engine *open() = 0; + virtual void close(Engine*); + const char *name; + struct engine_recovery recovery; struct rlist link; }; -extern struct rlist engines; - -/** Register engine instance. */ -void engine_register(struct engine *engine); - -/** Find engine by name. */ -struct engine *engine_find(const char *name); - -/** Init engine instance. */ -void engine_init(struct engine *instance, const char *name); +/** Engine handle */ +struct Engine: public Object { + Engine(EngineFactory *f); + virtual ~Engine() {} + + inline struct tuple* + replace(struct space *space, + struct tuple *old_tuple, + struct tuple *new_tuple, enum dup_replace_mode mode) + { + return recovery.replace(space, old_tuple, new_tuple, mode); + } + + inline void recover(struct space *space) { + recovery.recover(space); + } + + inline void recover_derive() { + recovery = host->recovery; + } + + engine_recovery recovery; + EngineFactory *host; +}; -/** Shutdown all engines. */ -void engine_shutdown(); +/** Register engine factory instance. */ +void engine_register(EngineFactory *engine); /** Call a visitor function on every registered engine. */ -void engine_foreach(void (*func)(struct engine *engine, void *udata), +void engine_foreach(void (*func)(EngineFactory *engine, void *udata), void *udata); -/** - * Derive recovery state from a parent engine - * handler. - */ -void engine_derive(struct engine *engine); +/** Find engine factory by name. */ +EngineFactory *engine_find(const char *name); -extern struct engine engine_memtx; +/** Shutdown all engines factories. */ +void engine_shutdown(); #endif /* TARANTOOL_BOX_ENGINE_H_INCLUDED */ diff --git a/src/box/engine_memtx.cc b/src/box/engine_memtx.cc new file mode 100644 index 0000000000000000000000000000000000000000..3e3a47a42fa4cc1b6054f19624f8f24c31c18514 --- /dev/null +++ b/src/box/engine_memtx.cc @@ -0,0 +1,78 @@ +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "tuple.h" +#include "engine.h" +#include "engine_memtx.h" +#include "space.h" +#include "exception.h" +#include "salad/rlist.h" +#include <stdlib.h> +#include <string.h> + +struct MEMTX_Engine: public Engine { + MEMTX_Engine(EngineFactory *e) + : Engine(e) + { } + virtual ~MEMTX_Engine() + { + /* do nothing */ + /* engine->close(this); */ + } +}; + +/** + * This is a vtab with which a newly created space which has no + * keys is primed. + * At first it is set to correctly work for spaces created during + * recovery from snapshot. In process of recovery it is updated as + * below: + * + * 1) after SNAP is loaded: + * recover = space_build_primary_key + * 2) when all XLOGs are loaded: + * recover = space_build_all_keys +*/ +static inline void +memtx_recovery_prepare(struct engine_recovery *r) +{ + r->state = READY_NO_KEYS; + r->recover = space_begin_build_primary_key; + r->replace = space_replace_no_keys; +} + +MEMTX::MEMTX() + :EngineFactory("memtx") +{ + memtx_recovery_prepare(&recovery); +} + +Engine *MEMTX::open() +{ + return new MEMTX_Engine(this); +} diff --git a/src/box/engine_memtx.h b/src/box/engine_memtx.h new file mode 100644 index 0000000000000000000000000000000000000000..e6d0cbb6a9daf0d03ffb43663531a05713ed18de --- /dev/null +++ b/src/box/engine_memtx.h @@ -0,0 +1,37 @@ +#ifndef TARANTOOL_BOX_ENGINE_MEMTX_H_INCLUDED +#define TARANTOOL_BOX_ENGINE_MEMTX_H_INCLUDED +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct MEMTX: public EngineFactory { + MEMTX(); + virtual Engine *open(); +}; + +#endif /* TARANTOOL_BOX_ENGINE_MEMTX_H_INCLUDED */ diff --git a/src/box/schema.cc b/src/box/schema.cc index e1d04da7c43b172d1de9d920a90e330f9573380f..2e023cfdd86058b65fd8575ae8679d5f39d06f71 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -166,12 +166,12 @@ static void do_one_recover_step(struct space *space, void * /* param */) { if (space_index(space, 0)) { - space->engine.recover(space); + space->engine->recover(space); } else { /* in case of space has no primary index, * derive it's engine handler recovery state from * the global one. */ - engine_derive(&space->engine); + space->engine->recover_derive(); } } @@ -198,9 +198,9 @@ sc_space_new(struct space_def *space_def, * ensures validation of tuples when starting from * a snapshot of older version. */ - space->engine.recover(space); /* load snapshot - begin */ - space->engine.recover(space); /* load snapshot - end */ - space->engine.recover(space); /* build secondary keys */ + space->engine->recover(space); /* load snapshot - begin */ + space->engine->recover(space); /* load snapshot - end */ + space->engine->recover(space); /* build secondary keys */ return space; } @@ -300,10 +300,10 @@ schema_init() } static inline void -space_end_recover_snapshot_cb(struct engine *engine, void *udate) +space_end_recover_snapshot_cb(EngineFactory *f, void *udate) { (void)udate; - engine->recover = space_build_primary_key; + f->recovery.recover = space_build_primary_key; } void @@ -325,10 +325,10 @@ fix_lua(struct space *space, void * /* param */) } static inline void -space_end_recover_cb(struct engine *engine, void *udate) +space_end_recover_cb(EngineFactory *f, void *udate) { (void)udate; - engine->recover = space_build_all_keys; + f->recovery.recover = space_build_all_keys; } void diff --git a/src/box/space.cc b/src/box/space.cc index 0c930073dacc22bcf2263e25c5667b98672f8e75..b7f3551a7950c258a08f934a80e9fb9c4172f9ca 100644 --- a/src/box/space.cc +++ b/src/box/space.cc @@ -77,7 +77,8 @@ space_new(struct space_def *def, struct rlist *key_list) tuple_format_ref(space->format, 1); space->index_id_max = index_id_max; /* init space engine instance */ - engine_init(&space->engine, def->engine_name); + EngineFactory *engine = engine_find(def->engine_name); + space->engine = engine->open(); /* fill space indexes */ rlist_foreach_entry(key_def, key_list, link) { space->index_map[key_def->iid] = Index::factory(key_def); @@ -95,6 +96,8 @@ space_delete(struct space *space) delete space->index[j]; if (space->format) tuple_format_ref(space->format, -1); + if (space->engine) + delete space->engine; struct trigger *trigger, *tmp; rlist_foreach_entry_safe(trigger, &space->on_replace, link, tmp) { @@ -228,9 +231,10 @@ space_build_secondary_keys(struct space *space) say_info("Space %d: done", space_id(space)); } } - space->engine.state = READY_ALL_KEYS; - space->engine.recover = space_noop; /* mark the end of recover */ - space->engine.replace = space_replace_all_keys; + engine_recovery *r = &space->engine->recovery; + r->state = READY_ALL_KEYS; + r->recover = space_noop; /* mark the end of recover */ + r->replace = space_replace_all_keys; } /** Build the primary key after loading data from a snapshot. */ @@ -238,9 +242,10 @@ void space_end_build_primary_key(struct space *space) { space->index[0]->endBuild(); - space->engine.state = READY_PRIMARY_KEY; - space->engine.replace = space_replace_primary_key; - space->engine.recover = space_build_secondary_keys; + engine_recovery *r = &space->engine->recovery; + r->state = READY_PRIMARY_KEY; + r->replace = space_replace_primary_key; + r->recover = space_build_secondary_keys; } /** Prepare the primary key for bulk load (loading from @@ -250,8 +255,9 @@ void space_begin_build_primary_key(struct space *space) { space->index[0]->beginBuild(); - space->engine.replace = space_replace_build_next; - space->engine.recover = space_end_build_primary_key; + engine_recovery *r = &space->engine->recovery; + r->replace = space_replace_build_next; + r->recover = space_end_build_primary_key; } /** diff --git a/src/box/space.h b/src/box/space.h index dfbfb7f0c28a727a23d037b2373bfb242e8b35eb..2ea00cfa4c5bfa5ca2b09f4b199abfd8951eeff5 100644 --- a/src/box/space.h +++ b/src/box/space.h @@ -42,7 +42,7 @@ struct space { * life cycle, throughout phases of recovery or with * deletion and addition of indexes. */ - struct engine engine; + Engine *engine; /** Triggers fired after space_replace() -- see txn_replace(). */ struct rlist on_replace; @@ -183,8 +183,7 @@ static inline struct tuple * space_replace(struct space *space, struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode) { - return space->engine.replace(space, old_tuple, new_tuple, - mode); + return space->engine->replace(space, old_tuple, new_tuple, mode); } struct tuple *