diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index 980678e2f7cb40ed45900db3095211b43a5551f1..a37523dceaf7190a287ccd3bc967eaf7f281c6b3 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -25,6 +25,8 @@ tarantool_module("box" hash_index.cc 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 74bb31ff5dc9d398156c3ef9240d21cb67cab31b..f19e311d4c450c31e43845953da6d069074758b3 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. */ - alter->new_space->engine = engine_no_keys; + alter->new_space->engine->initRecovery(); } 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 9bf639e61363396a7c486a79e759d95f418501f8..fc376105d77e30c278f5ae23eeb4ec1673150e11 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -46,6 +46,8 @@ extern "C" { #include "tuple.h" #include "lua/call.h" #include "schema.h" +#include "engine.h" +#include "engine_memtx.h" #include "space.h" #include "port.h" #include "request.h" @@ -273,9 +275,17 @@ box_free(void) schema_free(); tuple_free(); recovery_free(); + engine_shutdown(); stat_free(); } +static void +box_engine_init() +{ + MemtxFactory *memtx = new MemtxFactory(); + engine_register(memtx); +} + void box_init() { @@ -284,6 +294,9 @@ box_init() tuple_init(cfg.slab_alloc_arena, cfg.slab_alloc_minimal, cfg.slab_alloc_factor); + + box_engine_init(); + schema_init(); user_cache_init(); diff --git a/src/box/engine.cc b/src/box/engine.cc new file mode 100644 index 0000000000000000000000000000000000000000..578e5ca00164c559171399dba09d1d136537629d --- /dev/null +++ b/src/box/engine.cc @@ -0,0 +1,91 @@ +/* + * 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 "engine.h" +#include "space.h" +#include "exception.h" +#include "salad/rlist.h" +#include <stdlib.h> +#include <string.h> + +static RLIST_HEAD(engines); + +EngineFactory::EngineFactory(const char *engine_name) + :name(engine_name), + link(RLIST_INITIALIZER(link)) +{} + +void EngineFactory::init() +{} + +void EngineFactory::shutdown() +{} + +Engine::Engine(EngineFactory *f) + :factory(f) +{ + /* derive recovery state from engine factory */ + initRecovery(); +} + +/** Register engine factory instance. */ +void engine_register(EngineFactory *engine) +{ + rlist_add_entry(&engines, engine, link); +} + +/** Find factory engine by name. */ +EngineFactory * +engine_find(const char *name) +{ + EngineFactory *e; + rlist_foreach_entry(e, &engines, link) { + if (strcmp(e->name, name) == 0) + return e; + } + tnt_raise(LoggedError, ER_NO_SUCH_ENGINE, name); +} + +/** Call a visitor function on every registered engine. */ +void engine_foreach(void (*func)(EngineFactory *engine, void *udata), + void *udata) +{ + EngineFactory *e; + rlist_foreach_entry(e, &engines, link) + func(e, udata); +} + +/** Shutdown all engine factories. */ +void engine_shutdown() +{ + EngineFactory *e, *tmp; + rlist_foreach_entry_safe(e, &engines, link, tmp) { + e->shutdown(); + delete e; + } +} diff --git a/src/box/engine.h b/src/box/engine.h new file mode 100644 index 0000000000000000000000000000000000000000..fcb2462fd79e1181f1f9d06b60a5277e892fdb1e --- /dev/null +++ b/src/box/engine.h @@ -0,0 +1,143 @@ +#ifndef TARANTOOL_BOX_ENGINE_H_INCLUDED +#define TARANTOOL_BOX_ENGINE_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. + */ +#include <exception.h> +#include "index.h" + +struct space; +struct tuple; + +/** Reflects what space_replace() is supposed to do. */ +enum engine_recovery_state { + /** + * The space is created, but has no data + * and no primary key, or, if there is a primary + * key, it's not ready for use (being built with + * buildNext()). + * Replace is always an error, since there are no + * indexes to add data to. + */ + READY_NO_KEYS, + /** + * The space has a functional primary key. + * Replace adds the tuple to this key. + */ + READY_PRIMARY_KEY, + /** + * The space is fully functional, all keys + * are fully built, replace adds its tuple + * to all keys. + */ + READY_ALL_KEYS +}; + +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 + * at once and resets itself to a no-op. + */ + engine_recover_f recover; + engine_replace_f replace; +}; + +class Engine; + +/** Engine instance */ +class EngineFactory: public Object { +public: + EngineFactory(const char *engine_name); + virtual ~EngineFactory() {} + /** Called once at startup. */ + virtual void init(); + /** Called at server shutdown */ + virtual void shutdown(); + /** Create a new engine instance for a space. */ + virtual Engine *open() = 0; + /** + * Create an instance of space index. Used in alter + * space. + */ + virtual Index *createIndex(struct key_def*) = 0; +public: + /** Name of the engine. */ + const char *name; + struct engine_recovery recovery; + /** Used for search for engine by name. */ + struct rlist link; +}; + +/** Engine handle - an operator of a space */ + +struct Engine: public Object { +public: + 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 initRecovery() { + recovery = factory->recovery; + } + + engine_recovery recovery; + EngineFactory *factory; +}; + +/** Register engine factory instance. */ +void engine_register(EngineFactory *engine); + +/** Call a visitor function on every registered engine. */ +void engine_foreach(void (*func)(EngineFactory *engine, void *udata), + void *udata); + +/** Find engine factory by name. */ +EngineFactory *engine_find(const char *name); + +/** Shutdown all engine 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..f99d06b0a20ef0c86d202e1fa3af53e3cbee2a10 --- /dev/null +++ b/src/box/engine_memtx.cc @@ -0,0 +1,98 @@ +/* + * 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 "index.h" +#include "hash_index.h" +#include "tree_index.h" +#include "bitset_index.h" +#include "space.h" +#include "exception.h" +#include "salad/rlist.h" +#include <stdlib.h> +#include <string.h> + +struct Memtx: public Engine { + Memtx(EngineFactory *e) + : Engine(e) + { } + virtual ~Memtx() + { + /* 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; +} + +MemtxFactory::MemtxFactory() + :EngineFactory("memtx") +{ + memtx_recovery_prepare(&recovery); +} + +Engine *MemtxFactory::open() +{ + return new Memtx(this); +} + +Index * +MemtxFactory::createIndex(struct key_def *key_def) +{ + switch (key_def->type) { + case HASH: + return new HashIndex(key_def); + case TREE: + return new TreeIndex(key_def); + case BITSET: + return new BitsetIndex(key_def); + default: + assert(false); + return NULL; + } +} diff --git a/src/box/engine_memtx.h b/src/box/engine_memtx.h new file mode 100644 index 0000000000000000000000000000000000000000..14b8871fc2e361ce34882119af795e9cac80daad --- /dev/null +++ b/src/box/engine_memtx.h @@ -0,0 +1,38 @@ +#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 MemtxFactory: public EngineFactory { + MemtxFactory(); + virtual Engine *open(); + virtual Index *createIndex(struct key_def *key_def); +}; + +#endif /* TARANTOOL_BOX_ENGINE_MEMTX_H_INCLUDED */ diff --git a/src/box/index.cc b/src/box/index.cc index ecd52fde3c66e376d0f1c407141eb501dd4fc1b0..4860452c3ea492598dd5419c8e77ba9a3d040cfa 100644 --- a/src/box/index.cc +++ b/src/box/index.cc @@ -27,13 +27,8 @@ * SUCH DAMAGE. */ #include "index.h" -#include "hash_index.h" -#include "tree_index.h" -#include "bitset_index.h" -#include "tuple.h" #include "say.h" #include "exception.h" -#include <new> STRS(iterator_type, ITERATOR_TYPE); @@ -100,22 +95,6 @@ primary_key_validate(struct key_def *key_def, const char *key, /* {{{ Index -- base class for all indexes. ********************/ -Index * -Index::factory(struct key_def *key_def) -{ - switch (key_def->type) { - case HASH: - return new HashIndex(key_def); - case TREE: - return new TreeIndex(key_def); - case BITSET: - return new BitsetIndex(key_def); - default: - assert(false); - return NULL; /* silent compiler warning. */ - } -} - Index::Index(struct key_def *key_def_arg) :key_def(key_def_dup(key_def_arg)), m_position(NULL) diff --git a/src/box/index.h b/src/box/index.h index 4262b2dfbed4bc12f1b5e6b481f363bf903f6db1..862caa578178aa0248626f1ca0c3c3fef520d8c2 100644 --- a/src/box/index.h +++ b/src/box/index.h @@ -134,13 +134,6 @@ class Index: public Object { /* Description of a possibly multipart key. */ struct key_def *key_def; - /** - * Allocate index instance. - * - * @param key_def key part description - */ - static Index *factory(struct key_def *key_def); - protected: /** * Initialize index instance. diff --git a/src/box/key_def.h b/src/box/key_def.h index e9efbe3cc79f0edffc84b88e88821cf41cf2dd69..1b45972719b9d6ebb170a428394885aab81ce482 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -82,10 +82,10 @@ field_type_maxlen(enum field_type type) return maxlen[type]; } -#define ENUM_INDEX_TYPE(_) \ - _(HASH, 0) /* HASH Index */ \ - _(TREE, 1) /* TREE Index */ \ - _(BITSET, 2) /* BITSET Index */ \ +#define ENUM_INDEX_TYPE(_) \ + _(HASH, 0) /* HASH Index */ \ + _(TREE, 1) /* TREE Index */ \ + _(BITSET, 2) /* BITSET Index */ ENUM(index_type, ENUM_INDEX_TYPE); extern const char *index_type_strs[]; diff --git a/src/box/schema.cc b/src/box/schema.cc index 83399b6d1b915477e1ee610766973a7d9c37c339..fb38919620f258ee44e4126726f4760bc8adb879 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -28,6 +28,7 @@ */ #include "schema.h" #include "access.h" +#include "engine.h" #include "space.h" #include "tuple.h" #include "assoc.h" @@ -164,10 +165,14 @@ space_cache_replace(struct space *space) static void do_one_recover_step(struct space *space, void * /* param */) { - if (space_index(space, 0)) - space->engine.recover(space); - else - space->engine = engine_no_keys; + if (space_index(space, 0)) { + space->engine->recover(space); + } else { + /* in case of space has no primary index, + * derive it's engine handler recovery state from + * the global one. */ + space->engine->initRecovery(); + } } /** A wrapper around space_new() for data dictionary spaces. */ @@ -193,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; } @@ -241,7 +246,7 @@ schema_init() */ /* _schema - key/value space with schema description */ struct space_def def = { - SC_SCHEMA_ID, ADMIN, 0, "_schema", MEMTX, false + SC_SCHEMA_ID, ADMIN, 0, "_schema", "memtx", false }; struct key_def *key_def = key_def_new(def.id, 0 /* index id */, @@ -294,6 +299,13 @@ schema_init() key_def_delete(key_def); } +static inline void +space_end_recover_snapshot_cb(EngineFactory *f, void *udate) +{ + (void)udate; + f->recovery.recover = space_build_primary_key; +} + void space_end_recover_snapshot() { @@ -301,7 +313,8 @@ space_end_recover_snapshot() * For all new spaces created from now on, when the * PRIMARY key is added, enable it right away. */ - engine_no_keys.recover = space_build_primary_key; + engine_foreach(space_end_recover_snapshot_cb, NULL); + space_foreach(do_one_recover_step, NULL); } @@ -311,6 +324,13 @@ fix_lua(struct space *space, void * /* param */) box_lua_space_new(tarantool_L, space); } +static inline void +space_end_recover_cb(EngineFactory *f, void *udate) +{ + (void)udate; + f->recovery.recover = space_build_all_keys; +} + void space_end_recover() { @@ -318,8 +338,10 @@ space_end_recover() * For all new spaces created after recovery is complete, * when the primary key is added, enable all keys. */ - engine_no_keys.recover = space_build_all_keys; + engine_foreach(space_end_recover_cb, NULL); + space_foreach(do_one_recover_step, NULL); + /* TODO: temporary solution for Bug#1229709 */ space_foreach(fix_lua, NULL); } diff --git a/src/box/space.cc b/src/box/space.cc index d438fac6e305b79bed4f17e67210eea0b00dc6c0..cef92e2ce70b9fecc665259814b3bda64958d4af 100644 --- a/src/box/space.cc +++ b/src/box/space.cc @@ -34,15 +34,6 @@ #include "scoped_guard.h" #include "trigger.h" -static struct engine* -space_engine_find(const char *name) -{ - if (strcmp(name, MEMTX) == 0) - return &engine_no_keys; - - tnt_raise(LoggedError, ER_NO_SUCH_ENGINE, name); -} - void space_fill_index_map(struct space *space) { @@ -85,12 +76,15 @@ space_new(struct space_def *def, struct rlist *key_list) space->format = tuple_format_new(key_list); tuple_format_ref(space->format, 1); space->index_id_max = index_id_max; + /* init space engine instance */ + 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); + space->index_map[key_def->iid] = + space->engine->factory->createIndex(key_def); } space_fill_index_map(space); - space->engine = *space_engine_find(def->engine_name); space->run_triggers = true; scoped_guard.is_active = false; return space; @@ -103,6 +97,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) { @@ -236,9 +232,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. */ @@ -246,9 +243,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 @@ -258,8 +256,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; } /** @@ -287,24 +286,6 @@ space_build_all_keys(struct space *space) space_build_secondary_keys(space); } -/** - * 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_no_keys = { - /* .state = */ READY_NO_KEYS, - /* .recover = */ space_begin_build_primary_key, - /* .replace = */ space_replace_no_keys -}; - void space_validate_tuple(struct space *sp, struct tuple *new_tuple) { diff --git a/src/box/space.h b/src/box/space.h index 146700e27a1cecff26524d8d53a77a3147b13a64..2ea00cfa4c5bfa5ca2b09f4b199abfd8951eeff5 100644 --- a/src/box/space.h +++ b/src/box/space.h @@ -30,55 +30,10 @@ */ #include "index.h" #include "key_def.h" +#include "engine.h" #include "salad/rlist.h" #include <exception.h> -typedef void (*space_f)(struct space *space); -typedef struct tuple *(*space_replace_f) - (struct space *space, struct tuple *old_tuple, - struct tuple *new_tuple, enum dup_replace_mode mode); - -/** Reflects what space_replace() is supposed to do. */ -enum space_state { - /** - * The space is created, but has no data - * and no primary key, or, if there is a primary - * key, it's not ready for use (being built with - * buildNext()). - * Replace is always an error, since there are no - * indexes to add data to. - */ - READY_NO_KEYS, - /** - * The space has a functional primary key. - * Replace adds the tuple to this key. - */ - READY_PRIMARY_KEY, - /** - * The space is fully functional, all keys - * are fully built, replace adds its tuple - * to all keys. - */ - READY_ALL_KEYS -}; - -struct engine { - enum space_state state; - /* Recover is called after each recover step to enable - * keys. When recovery is complete, it enables all keys - * at once and resets itself to a no-op. - */ - space_f recover; - space_replace_f replace; -}; - -#define MEMTX "memtx" - -extern struct engine engine_no_keys; - -void space_build_primary_key(struct space *space); -void space_build_all_keys(struct space *space); - struct space { uint8_t access[BOX_USER_MAX]; /** @@ -87,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; @@ -228,10 +183,17 @@ 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 * +space_replace_no_keys(struct space*, struct tuple*, struct tuple*, + enum dup_replace_mode); + +void space_begin_build_primary_key(struct space *space); +void space_build_primary_key(struct space *space); +void space_build_all_keys(struct space *space); + uint32_t space_size(struct space *space); diff --git a/src/lib/salad/rlist.h b/src/lib/salad/rlist.h index d5226be162461cd224576134dc0ef64dde11bcc7..7952d07cf5157732f5a6dea3e26b5415e4087947 100644 --- a/src/lib/salad/rlist.h +++ b/src/lib/salad/rlist.h @@ -191,11 +191,16 @@ rlist_swap(struct rlist *rhs, struct rlist *lhs) rhs->prev->next = rhs; } +/** + * list initializer + */ +#define RLIST_INITIALIZER(name) { &(name), &(name) } + /** * allocate and init head of list */ #define RLIST_HEAD(name) \ - struct rlist name = { &(name), &(name) } + struct rlist name = RLIST_INITIALIZER(name) /** * return entry by list item