From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 6AE0A251C3 for ; Thu, 17 May 2018 15:23:33 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id e1tsEeFYtC15 for ; Thu, 17 May 2018 15:23:33 -0400 (EDT) Received: from smtp33.i.mail.ru (smtp33.i.mail.ru [94.100.177.93]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id AA544250E7 for ; Thu, 17 May 2018 15:23:31 -0400 (EDT) Subject: [tarantool-patches] Re: [PATCH v3 2/4] collation: split collation into core and box objects From: Vladislav Shpilevoy References: Message-ID: <603449c6-ee92-9f5e-67b3-8e56bd854286@tarantool.org> Date: Thu, 17 May 2018 22:23:27 +0300 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: kostja@tarantool.org Hello. Below the new patch is presented. Here box_coll is renamed to coll_id, and stack buffers are removed from coll.c. --- collation: split collation into coll and id objects In the issue #3290 the important problem appeared - Tarantool can not create completely internal collations with no ID, name, owner. Just for internal usage. Original struct coll can not be used for this since * it has fields that are not needed in internals; * collation name is public thing, and the collation cache uses it, so it would be necessary to forbid to a user usage of some system names; * when multiple collations has the same comparator and only their names/owners/IDs are different, the separate UCollator objects are created, but it would be good to be able to reference a single one. This patch renames coll to coll_id, coll_def to call_id_def and introduces coll - pure collation object with no any user defined things. Needed for #3290. --- src/CMakeLists.txt | 2 + src/box/CMakeLists.txt | 6 +- src/box/alter.cc | 105 ++++++++++---------- src/box/coll_id.c | 65 +++++++++++++ src/box/coll_id.h | 77 +++++++++++++++ src/box/{coll_cache.c => coll_id_cache.c} | 62 +++++------- src/box/{coll_cache.h => coll_id_cache.h} | 27 +++--- src/box/{coll_def.c => coll_id_def.c} | 34 +------ src/box/coll_id_def.h | 54 +++++++++++ src/box/error.cc | 2 + src/box/key_def.cc | 23 +++-- src/box/key_def.h | 7 +- src/box/lua/space.cc | 8 +- src/box/schema.cc | 8 +- src/box/tuple.c | 6 +- src/box/tuple_compare.cc | 5 +- src/box/tuple_hash.cc | 1 - src/{box => }/coll.c | 153 +++++++++++------------------- src/{box => }/coll.h | 37 +++----- src/coll_def.c | 63 ++++++++++++ src/{box => }/coll_def.h | 35 ++----- src/diag.h | 2 + src/exception.cc | 24 +++++ src/exception.h | 9 ++ test/unit/coll.cpp | 8 +- 25 files changed, 505 insertions(+), 318 deletions(-) create mode 100644 src/box/coll_id.c create mode 100644 src/box/coll_id.h rename src/box/{coll_cache.c => coll_id_cache.c} (56%) rename src/box/{coll_cache.h => coll_id_cache.h} (78%) rename src/box/{coll_def.c => coll_id_def.c} (86%) create mode 100644 src/box/coll_id_def.h rename src/{box => }/coll.c (63%) rename src/{box => }/coll.h (74%) create mode 100644 src/coll_def.c rename src/{box => }/coll_def.h (82%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ab09e968..5bf17614b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,6 +94,8 @@ set (core_sources random.c trigger.cc http_parser.c + coll.c + coll_def.c ) if (TARGET_OS_NETBSD) diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index 866b7b75c..e84e791df 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -41,9 +41,9 @@ add_library(tuple STATIC tuple_bloom.c tuple_dictionary.c key_def.cc - coll_def.c - coll.c - coll_cache.c + coll_id_def.c + coll_id.c + coll_id_cache.c field_def.c opt_def.c ) diff --git a/src/box/alter.cc b/src/box/alter.cc index 8766c8171..7858af989 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -34,7 +34,8 @@ #include "space.h" #include "index.h" #include "func.h" -#include "coll_cache.h" +#include "coll_id_cache.h" +#include "coll_id_def.h" #include "txn.h" #include "tuple.h" #include "fiber.h" /* for gc_pool */ @@ -2284,9 +2285,9 @@ on_replace_dd_func(struct trigger * /* trigger */, void *event) } } -/** Create a collation definition from tuple. */ +/** Create a collation identifier definition from tuple. */ void -coll_def_new_from_tuple(const struct tuple *tuple, struct coll_def *def) +coll_id_def_new_from_tuple(const struct tuple *tuple, struct coll_id_def *def) { memset(def, 0, sizeof(*def)); uint32_t name_len, locale_len, type_len; @@ -2294,15 +2295,16 @@ coll_def_new_from_tuple(const struct tuple *tuple, struct coll_def *def) def->name = tuple_field_str_xc(tuple, BOX_COLLATION_FIELD_NAME, &name_len); def->name_len = name_len; def->owner_id = tuple_field_u32_xc(tuple, BOX_COLLATION_FIELD_UID); + struct coll_def *base = &def->base; const char *type = tuple_field_str_xc(tuple, BOX_COLLATION_FIELD_TYPE, &type_len); - def->type = STRN2ENUM(coll_type, type, type_len); - if (def->type == coll_type_MAX) + base->type = STRN2ENUM(coll_type, type, type_len); + if (base->type == coll_type_MAX) tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "unknown collation type"); - def->locale = tuple_field_str_xc(tuple, BOX_COLLATION_FIELD_LOCALE, - &locale_len); - def->locale_len = locale_len; + base->locale = tuple_field_str_xc(tuple, BOX_COLLATION_FIELD_LOCALE, + &locale_len); + base->locale_len = locale_len; const char *options = tuple_field_with_type_xc(tuple, BOX_COLLATION_FIELD_OPTIONS, MP_MAP); @@ -2315,53 +2317,53 @@ coll_def_new_from_tuple(const struct tuple *tuple, struct coll_def *def) "collation locale is too long"); /* Locale is an optional argument and can be NULL. */ if (locale_len > 0) - identifier_check_xc(def->locale, locale_len); + identifier_check_xc(base->locale, locale_len); identifier_check_xc(def->name, name_len); - assert(def->type == COLL_TYPE_ICU); /* no more defined now */ - if (opts_decode(&def->icu, coll_icu_opts_reg, &options, + assert(base->type == COLL_TYPE_ICU); + if (opts_decode(&base->icu, coll_icu_opts_reg, &options, ER_WRONG_COLLATION_OPTIONS, BOX_COLLATION_FIELD_OPTIONS, NULL) != 0) diag_raise(); - if (def->icu.french_collation == coll_icu_on_off_MAX) { + if (base->icu.french_collation == coll_icu_on_off_MAX) { tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "ICU wrong french_collation option setting, " "expected ON | OFF"); } - if (def->icu.alternate_handling == coll_icu_alternate_handling_MAX) { + if (base->icu.alternate_handling == coll_icu_alternate_handling_MAX) { tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "ICU wrong alternate_handling option setting, " "expected NON_IGNORABLE | SHIFTED"); } - if (def->icu.case_first == coll_icu_case_first_MAX) { + if (base->icu.case_first == coll_icu_case_first_MAX) { tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "ICU wrong case_first option setting, " "expected OFF | UPPER_FIRST | LOWER_FIRST"); } - if (def->icu.case_level == coll_icu_on_off_MAX) { + if (base->icu.case_level == coll_icu_on_off_MAX) { tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "ICU wrong case_level option setting, " "expected ON | OFF"); } - if (def->icu.normalization_mode == coll_icu_on_off_MAX) { + if (base->icu.normalization_mode == coll_icu_on_off_MAX) { tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "ICU wrong normalization_mode option setting, " "expected ON | OFF"); } - if (def->icu.strength == coll_icu_strength_MAX) { + if (base->icu.strength == coll_icu_strength_MAX) { tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "ICU wrong strength option setting, " "expected PRIMARY | SECONDARY | " "TERTIARY | QUATERNARY | IDENTICAL"); } - if (def->icu.numeric_collation == coll_icu_on_off_MAX) { + if (base->icu.numeric_collation == coll_icu_on_off_MAX) { tnt_raise(ClientError, ER_CANT_CREATE_COLLATION, "ICU wrong numeric_collation option setting, " "expected ON | OFF"); @@ -2373,36 +2375,36 @@ coll_def_new_from_tuple(const struct tuple *tuple, struct coll_def *def) * A change is only INSERT or DELETE, UPDATE is not supported. */ static void -coll_cache_rollback(struct trigger *trigger, void *event) +coll_id_cache_rollback(struct trigger *trigger, void *event) { - struct coll *coll = (struct coll *) trigger->data; + struct coll_id *coll_id = (struct coll_id *) trigger->data; struct txn_stmt *stmt = txn_last_stmt((struct txn*) event); if (stmt->new_tuple == NULL) { - /* Rollback DELETE: put the collation back. */ + /* DELETE: put the collation identifier back. */ assert(stmt->old_tuple != NULL); - struct coll *replaced; - if (coll_cache_replace(coll, &replaced) != 0) { + struct coll_id *replaced_id; + if (coll_id_cache_replace(coll_id, &replaced_id) != 0) { panic("Out of memory on insertion into collation "\ "cache"); } - assert(replaced == NULL); + assert(replaced_id == NULL); } else { - /* INSERT: remove and free the new collation */ + /* INSERT: delete the new collation identifier. */ assert(stmt->old_tuple == NULL); - coll_cache_delete(coll); - coll_unref(coll); + coll_id_cache_delete(coll_id); + coll_id_delete(coll_id); } } -/** Dereference a deleted collation on commit. */ +/** Free a deleted collation identifier on commit. */ static void -coll_cache_commit(struct trigger *trigger, void *event) +coll_id_cache_commit(struct trigger *trigger, void *event) { (void) event; - struct coll *coll = (struct coll *) trigger->data; - coll_unref(coll); + struct coll_id *coll_id = (struct coll_id *) trigger->data; + coll_id_delete(coll_id); } /** @@ -2418,44 +2420,47 @@ on_replace_dd_collation(struct trigger * /* trigger */, void *event) struct tuple *new_tuple = stmt->new_tuple; txn_check_singlestatement_xc(txn, "Space _collation"); struct trigger *on_rollback = - txn_alter_trigger_new(coll_cache_rollback, NULL); + txn_alter_trigger_new(coll_id_cache_rollback, NULL); struct trigger *on_commit = - txn_alter_trigger_new(coll_cache_commit, NULL); + txn_alter_trigger_new(coll_id_cache_commit, NULL); if (new_tuple == NULL && old_tuple != NULL) { /* DELETE */ - /* TODO: Check that no index uses the collation */ + /* + * TODO: Check that no index uses the collation + * identifier. + */ int32_t old_id = tuple_field_u32_xc(old_tuple, BOX_COLLATION_FIELD_ID); - struct coll *old_coll = coll_by_id(old_id); - assert(old_coll != NULL); - access_check_ddl(old_coll->name, old_coll->owner_id, + struct coll_id *old_coll_id = coll_by_id(old_id); + assert(old_coll_id != NULL); + access_check_ddl(old_coll_id->name, old_coll_id->owner_id, SC_COLLATION, PRIV_D, false); /* * Set on_commit/on_rollback triggers after * deletion from the cache to make trigger logic - * simple.. + * simple. */ - coll_cache_delete(old_coll); - on_rollback->data = old_coll; - on_commit->data = old_coll; + coll_id_cache_delete(old_coll_id); + on_rollback->data = old_coll_id; + on_commit->data = old_coll_id; txn_on_rollback(txn, on_rollback); txn_on_commit(txn, on_commit); } else if (new_tuple != NULL && old_tuple == NULL) { /* INSERT */ - struct coll_def new_def; - coll_def_new_from_tuple(new_tuple, &new_def); + struct coll_id_def new_def; + coll_id_def_new_from_tuple(new_tuple, &new_def); access_check_ddl(new_def.name, new_def.owner_id, SC_COLLATION, PRIV_C, false); - struct coll *new_coll = coll_new(&new_def); - if (new_coll == NULL) + struct coll_id *new_coll_id = coll_id_new(&new_def); + if (new_coll_id == NULL) diag_raise(); - struct coll *replaced; - if (coll_cache_replace(new_coll, &replaced) != 0) { - coll_unref(new_coll); + struct coll_id *replaced_id; + if (coll_id_cache_replace(new_coll_id, &replaced_id) != 0) { + coll_id_delete(new_coll_id); diag_raise(); } - assert(replaced == NULL); - on_rollback->data = new_coll; + assert(replaced_id == NULL); + on_rollback->data = new_coll_id; txn_on_rollback(txn, on_rollback); } else { /* UPDATE */ diff --git a/src/box/coll_id.c b/src/box/coll_id.c new file mode 100644 index 000000000..2d5f8a09a --- /dev/null +++ b/src/box/coll_id.c @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * + * 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 AUTHORS ``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 + * AUTHORS 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 "coll_id.h" +#include "coll_id_def.h" +#include "coll.h" +#include "error.h" +#include "diag.h" + +struct coll_id * +coll_id_new(const struct coll_id_def *def) +{ + assert(def->base.type == COLL_TYPE_ICU); + size_t total_len = sizeof(struct coll_id) + def->name_len + 1; + struct coll_id *coll_id = (struct coll_id *) malloc(total_len); + if (coll_id == NULL) { + diag_set(OutOfMemory, total_len, "malloc", "coll_id"); + return NULL; + } + coll_id->coll = coll_new(&def->base); + if (coll_id->coll == NULL) { + free(coll_id); + return NULL; + } + coll_id->id = def->id; + coll_id->owner_id = def->owner_id; + coll_id->name_len = def->name_len; + memcpy(coll_id->name, def->name, def->name_len); + coll_id->name[coll_id->name_len] = 0; + return coll_id; +} + +void +coll_id_delete(struct coll_id *coll_id) +{ + coll_unref(coll_id->coll); + free(coll_id); +} diff --git a/src/box/coll_id.h b/src/box/coll_id.h new file mode 100644 index 000000000..1b67a3f86 --- /dev/null +++ b/src/box/coll_id.h @@ -0,0 +1,77 @@ +#ifndef TARANTOOL_BOX_COLL_ID_H_INCLUDED +#define TARANTOOL_BOX_COLL_ID_H_INCLUDED +/* + * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * + * 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 AUTHORS ``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 + * AUTHORS 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 +#include + +#if defined(__cplusplus) +extern "C" { +#endif /* defined(__cplusplus) */ + +struct coll_id_def; +struct coll; + +/** + * A collation identifier. It gives a name, owner and unique + * identifier to a base collation. Multiple coll_id can reference + * the same collation if their functional parts match. + */ +struct coll_id { + /** Personal ID */ + uint32_t id; + /** Owner ID */ + uint32_t owner_id; + /** Collation object. */ + struct coll *coll; + /** Collation name. */ + size_t name_len; + char name[0]; +}; + +/** + * Create a collation identifier by definition. + * @param def Collation definition. + * @retval NULL Illegal parameters or memory error. + * @retval not NULL Collation. + */ +struct coll_id * +coll_id_new(const struct coll_id_def *def); + +/** Delete collation identifier, unref the basic collation. */ +void +coll_id_delete(struct coll_id *coll); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + +#endif /* TARANTOOL_BOX_COLL_ID_H_INCLUDED */ diff --git a/src/box/coll_cache.c b/src/box/coll_id_cache.c similarity index 56% rename from src/box/coll_cache.c rename to src/box/coll_id_cache.c index b7eb3edb9..122863937 100644 --- a/src/box/coll_cache.c +++ b/src/box/coll_id_cache.c @@ -28,75 +28,63 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include "coll_cache.h" +#include "coll_id_cache.h" +#include "coll_id.h" #include "diag.h" #include "assoc.h" /** mhash table (id -> collation) */ -static struct mh_i32ptr_t *coll_cache_id = NULL; +static struct mh_i32ptr_t *coll_id_cache = NULL; -/** Create global hash tables if necessary. */ int -coll_cache_init() +coll_id_cache_init() { - coll_cache_id = mh_i32ptr_new(); - if (coll_cache_id == NULL) { - diag_set(OutOfMemory, sizeof(*coll_cache_id), "malloc", - "coll_cache_id"); + coll_id_cache = mh_i32ptr_new(); + if (coll_id_cache == NULL) { + diag_set(OutOfMemory, sizeof(*coll_id_cache), "malloc", + "coll_id_cache"); return -1; } return 0; } -/** Delete global hash tables. */ void -coll_cache_destroy() +coll_id_cache_destroy() { - mh_i32ptr_delete(coll_cache_id); + mh_i32ptr_delete(coll_id_cache); } -/** - * Insert or replace a collation into collation cache. - * @param coll - collation to insert/replace. - * @return - NULL if inserted, replaced collation if replaced. - */ int -coll_cache_replace(struct coll *coll, struct coll **replaced) +coll_id_cache_replace(struct coll_id *coll_id, struct coll_id **replaced_id) { - const struct mh_i32ptr_node_t id_node = {coll->id, coll}; + const struct mh_i32ptr_node_t id_node = {coll_id->id, coll_id}; struct mh_i32ptr_node_t repl_id_node = {0, NULL}; struct mh_i32ptr_node_t *prepl_id_node = &repl_id_node; - if (mh_i32ptr_put(coll_cache_id, &id_node, &prepl_id_node, NULL) == - mh_end(coll_cache_id)) { - diag_set(OutOfMemory, sizeof(id_node), "malloc", "coll_cache_id"); + if (mh_i32ptr_put(coll_id_cache, &id_node, &prepl_id_node, NULL) == + mh_end(coll_id_cache)) { + diag_set(OutOfMemory, sizeof(id_node), "malloc", + "coll_id_cache"); return -1; } assert(repl_id_node.val == NULL); - *replaced = repl_id_node.val; + *replaced_id = repl_id_node.val; return 0; } -/** - * Delete a collation from collation cache. - * @param coll - collation to delete. - */ void -coll_cache_delete(const struct coll *coll) +coll_id_cache_delete(const struct coll_id *coll_id) { - mh_int_t i = mh_i32ptr_find(coll_cache_id, coll->id, NULL); - if (i == mh_end(coll_cache_id)) + mh_int_t i = mh_i32ptr_find(coll_id_cache, coll_id->id, NULL); + if (i == mh_end(coll_id_cache)) return; - mh_i32ptr_del(coll_cache_id, i, NULL); + mh_i32ptr_del(coll_id_cache, i, NULL); } -/** - * Find a collation object by its id. - */ -struct coll * +struct coll_id * coll_by_id(uint32_t id) { - mh_int_t pos = mh_i32ptr_find(coll_cache_id, id, NULL); - if (pos == mh_end(coll_cache_id)) + mh_int_t pos = mh_i32ptr_find(coll_id_cache, id, NULL); + if (pos == mh_end(coll_id_cache)) return NULL; - return mh_i32ptr_node(coll_cache_id, pos)->val; + return mh_i32ptr_node(coll_id_cache, pos)->val; } diff --git a/src/box/coll_cache.h b/src/box/coll_id_cache.h similarity index 78% rename from src/box/coll_cache.h rename to src/box/coll_id_cache.h index 418de4e35..4bbbc85de 100644 --- a/src/box/coll_cache.h +++ b/src/box/coll_id_cache.h @@ -1,5 +1,5 @@ -#ifndef TARANTOOL_BOX_COLL_CACHE_H_INCLUDED -#define TARANTOOL_BOX_COLL_CACHE_H_INCLUDED +#ifndef TARANTOOL_BOX_COLL_ID_CACHE_H_INCLUDED +#define TARANTOOL_BOX_COLL_ID_CACHE_H_INCLUDED /* * Copyright 2010-2016, Tarantool AUTHORS, please see AUTHORS file. * @@ -30,48 +30,49 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - -#include "coll.h" +#include #if defined(__cplusplus) extern "C" { #endif /* defined(__cplusplus) */ +struct coll_id; + /** * Create global hash tables. * @return - 0 on success, -1 on memory error. */ int -coll_cache_init(); +coll_id_cache_init(); /** Delete global hash tables. */ void -coll_cache_destroy(); +coll_id_cache_destroy(); /** * Insert or replace a collation into collation cache. - * @param coll - collation to insert/replace. - * @param replaced - collation that was replaced. + * @param coll_id Collation to insert/replace. + * @param Replaced_id Collation that was replaced. * @return - 0 on success, -1 on memory error. */ int -coll_cache_replace(struct coll *coll, struct coll **replaced); +coll_id_cache_replace(struct coll_id *coll_id, struct coll_id **replaced_id); /** * Delete a collation from collation cache. - * @param coll - collation to delete. + * @param coll_id Collation to delete. */ void -coll_cache_delete(const struct coll *coll); +coll_id_cache_delete(const struct coll_id *coll_id); /** * Find a collation object by its id. */ -struct coll * +struct coll_id * coll_by_id(uint32_t id); #if defined(__cplusplus) } /* extern "C" */ #endif /* defined(__cplusplus) */ -#endif /* TARANTOOL_BOX_COLL_CACHE_H_INCLUDED */ +#endif /* TARANTOOL_BOX_COLL_ID_CACHE_H_INCLUDED */ diff --git a/src/box/coll_def.c b/src/box/coll_id_def.c similarity index 86% rename from src/box/coll_def.c rename to src/box/coll_id_def.c index f849845b3..9fe0cda8c 100644 --- a/src/box/coll_def.c +++ b/src/box/coll_id_def.c @@ -29,39 +29,7 @@ * SUCH DAMAGE. */ -#include "coll_def.h" - -const char *coll_type_strs[] = { - "ICU" -}; - -const char *coll_icu_on_off_strs[] = { - "DEFAULT", - "ON", - "OFF" -}; - -const char *coll_icu_alternate_handling_strs[] = { - "DEFAULT", - "NON_IGNORABLE", - "SHIFTED" -}; - -const char *coll_icu_case_first_strs[] = { - "DEFAULT", - "OFF", - "UPPER_FIRST", - "LOWER_FIRST" -}; - -const char *coll_icu_strength_strs[] = { - "DEFAULT", - "PRIMARY", - "SECONDARY", - "TERTIARY", - "QUATERNARY", - "IDENTICAL" -}; +#include "coll_id_def.h" static int64_t icu_on_off_from_str(const char *str, uint32_t len) diff --git a/src/box/coll_id_def.h b/src/box/coll_id_def.h new file mode 100644 index 000000000..489280c00 --- /dev/null +++ b/src/box/coll_id_def.h @@ -0,0 +1,54 @@ +#ifndef TARANTOOL_BOX_COLL_ID_DEF_H_INCLUDED +#define TARANTOOL_BOX_COLL_ID_DEF_H_INCLUDED +/* + * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * + * 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 AUTHORS ``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 + * AUTHORS 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 +#include +#include +#include "opt_def.h" + +/** Collation identifier definition. */ +struct coll_id_def { + /** Perconal ID */ + uint32_t id; + /** Owner ID */ + uint32_t owner_id; + /** Collation name. */ + size_t name_len; + const char *name; + /** Core collation definition. */ + struct coll_def base; +}; + +extern const struct opt_def coll_icu_opts_reg[]; + +#endif /* TARANTOOL_BOX_COLL_ID_DEF_H_INCLUDED */ diff --git a/src/box/error.cc b/src/box/error.cc index 99f519537..6b14dff05 100644 --- a/src/box/error.cc +++ b/src/box/error.cc @@ -155,6 +155,8 @@ ClientError::get_errcode(const struct error *e) return ER_MEMORY_ISSUE; if (type_cast(SystemError, e)) return ER_SYSTEM; + if (type_cast(CollationError, e)) + return ER_CANT_CREATE_COLLATION; return ER_PROC_LUA; } diff --git a/src/box/key_def.cc b/src/box/key_def.cc index 45997ae83..ee09dc99d 100644 --- a/src/box/key_def.cc +++ b/src/box/key_def.cc @@ -34,7 +34,7 @@ #include "tuple_hash.h" #include "column_mask.h" #include "schema_def.h" -#include "coll_cache.h" +#include "coll_id_cache.h" static const struct key_part_def key_part_def_default = { 0, @@ -156,16 +156,17 @@ key_def_new_with_parts(struct key_part_def *parts, uint32_t part_count) struct key_part_def *part = &parts[i]; struct coll *coll = NULL; if (part->coll_id != COLL_NONE) { - coll = coll_by_id(part->coll_id); - if (coll == NULL) { + struct coll_id *coll_id = coll_by_id(part->coll_id); + if (coll_id == NULL) { diag_set(ClientError, ER_WRONG_INDEX_OPTIONS, i + 1, "collation was not found by ID"); key_def_delete(def); return NULL; } + coll = coll_id->coll; } key_def_set_part(def, i, part->fieldno, part->type, - part->is_nullable, coll); + part->is_nullable, coll, part->coll_id); } return def; } @@ -179,8 +180,7 @@ key_def_dump_parts(const struct key_def *def, struct key_part_def *parts) part_def->fieldno = part->fieldno; part_def->type = part->type; part_def->is_nullable = part->is_nullable; - part_def->coll_id = (part->coll != NULL ? - part->coll->id : COLL_NONE); + part_def->coll_id = part->coll_id; } } @@ -194,7 +194,8 @@ box_key_def_new(uint32_t *fields, uint32_t *types, uint32_t part_count) for (uint32_t item = 0; item < part_count; ++item) { key_def_set_part(key_def, item, fields[item], (enum field_type)types[item], - key_part_def_default.is_nullable, NULL); + key_part_def_default.is_nullable, NULL, + COLL_NONE); } return key_def; } @@ -246,7 +247,8 @@ key_part_cmp(const struct key_part *parts1, uint32_t part_count1, void key_def_set_part(struct key_def *def, uint32_t part_no, uint32_t fieldno, - enum field_type type, bool is_nullable, struct coll *coll) + enum field_type type, bool is_nullable, struct coll *coll, + uint32_t coll_id) { assert(part_no < def->part_count); assert(type < field_type_MAX); @@ -255,6 +257,7 @@ key_def_set_part(struct key_def *def, uint32_t part_no, uint32_t fieldno, def->parts[part_no].fieldno = fieldno; def->parts[part_no].type = type; def->parts[part_no].coll = coll; + def->parts[part_no].coll_id = coll_id; column_mask_set_fieldno(&def->column_mask, fieldno); /** * When all parts are set, initialize the tuple @@ -554,7 +557,7 @@ key_def_merge(const struct key_def *first, const struct key_def *second) end = part + first->part_count; for (; part != end; part++) { key_def_set_part(new_def, pos++, part->fieldno, part->type, - part->is_nullable, part->coll); + part->is_nullable, part->coll, part->coll_id); } /* Set-append second key def's part to the new key def. */ @@ -564,7 +567,7 @@ key_def_merge(const struct key_def *first, const struct key_def *second) if (key_def_find(first, part->fieldno)) continue; key_def_set_part(new_def, pos++, part->fieldno, part->type, - part->is_nullable, part->coll); + part->is_nullable, part->coll, part->coll_id); } return new_def; } diff --git a/src/box/key_def.h b/src/box/key_def.h index 12016a51a..aecbe0345 100644 --- a/src/box/key_def.h +++ b/src/box/key_def.h @@ -36,7 +36,7 @@ #include #include #include "field_def.h" -#include "coll.h" +#include "coll_id.h" #if defined(__cplusplus) extern "C" { @@ -68,6 +68,8 @@ struct key_part { uint32_t fieldno; /** Type of the tuple field */ enum field_type type; + /** Collation ID for string comparison. */ + uint32_t coll_id; /** Collation definition for string comparison */ struct coll *coll; /** True if a part can store NULLs. */ @@ -249,7 +251,8 @@ key_def_dump_parts(const struct key_def *def, struct key_part_def *parts); */ void key_def_set_part(struct key_def *def, uint32_t part_no, uint32_t fieldno, - enum field_type type, bool is_nullable, struct coll *coll); + enum field_type type, bool is_nullable, struct coll *coll, + uint32_t coll_id); /** * Update 'has_optional_parts' of @a key_def with correspondence diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc index 333b6370f..524382750 100644 --- a/src/box/lua/space.cc +++ b/src/box/lua/space.cc @@ -46,6 +46,7 @@ extern "C" { #include "box/txn.h" #include "box/vclock.h" /* VCLOCK_MAX */ #include "box/sequence.h" +#include "box/coll_id_cache.h" /** * Trigger function for all spaces @@ -291,8 +292,11 @@ lbox_fillspace(struct lua_State *L, struct space *space, int i) lua_pushboolean(L, part->is_nullable); lua_setfield(L, -2, "is_nullable"); - if (part->coll != NULL) { - lua_pushstring(L, part->coll->name); + if (part->coll_id != COLL_NONE) { + struct coll_id *coll_id = + coll_by_id(part->coll_id); + assert(coll_id != NULL); + lua_pushstring(L, coll_id->name); lua_setfield(L, -2, "collation"); } diff --git a/src/box/schema.cc b/src/box/schema.cc index 1b96f978c..8df4aa73b 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -281,13 +281,13 @@ schema_init() auto key_def_guard = make_scoped_guard([&] { key_def_delete(key_def); }); key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_STRING, false, NULL); + FIELD_TYPE_STRING, false, NULL, COLL_NONE); sc_space_new(BOX_SCHEMA_ID, "_schema", key_def, &on_replace_schema, NULL); /* _space - home for all spaces. */ key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_UNSIGNED, false, NULL); + FIELD_TYPE_UNSIGNED, false, NULL, COLL_NONE); /* _collation - collation description. */ sc_space_new(BOX_COLLATION_ID, "_collation", key_def, @@ -335,10 +335,10 @@ schema_init() diag_raise(); /* space no */ key_def_set_part(key_def, 0 /* part no */, 0 /* field no */, - FIELD_TYPE_UNSIGNED, false, NULL); + FIELD_TYPE_UNSIGNED, false, NULL, COLL_NONE); /* index no */ key_def_set_part(key_def, 1 /* part no */, 1 /* field no */, - FIELD_TYPE_UNSIGNED, false, NULL); + FIELD_TYPE_UNSIGNED, false, NULL, COLL_NONE); sc_space_new(BOX_INDEX_ID, "_index", key_def, &alter_space_on_replace_index, &on_stmt_begin_index); } diff --git a/src/box/tuple.c b/src/box/tuple.c index d4760f3b1..cf3929734 100644 --- a/src/box/tuple.c +++ b/src/box/tuple.c @@ -38,7 +38,7 @@ #include "small/small.h" #include "tuple_update.h" -#include "coll_cache.h" +#include "coll_id_cache.h" static struct mempool tuple_iterator_pool; static struct small_alloc runtime_alloc; @@ -207,7 +207,7 @@ tuple_init(field_name_hash_f hash) box_tuple_last = NULL; - if (coll_cache_init() != 0) + if (coll_id_cache_init() != 0) return -1; return 0; @@ -260,7 +260,7 @@ tuple_free(void) tuple_format_free(); - coll_cache_destroy(); + coll_id_cache_destroy(); } box_tuple_format_t * diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc index cfee00496..e53afba42 100644 --- a/src/box/tuple_compare.cc +++ b/src/box/tuple_compare.cc @@ -30,9 +30,9 @@ */ #include "tuple_compare.h" #include "tuple.h" +#include "coll.h" #include "trivia/util.h" /* NOINLINE */ #include -#include "coll_def.h" /* {{{ tuple_compare */ @@ -295,8 +295,7 @@ mp_compare_str(const char *field_a, const char *field_b) } static inline int -mp_compare_str_coll(const char *field_a, const char *field_b, - struct coll *coll) +mp_compare_str_coll(const char *field_a, const char *field_b, struct coll *coll) { uint32_t size_a = mp_decode_strl(&field_a); uint32_t size_b = mp_decode_strl(&field_b); diff --git a/src/box/tuple_hash.cc b/src/box/tuple_hash.cc index 0fa8ea561..dee9be328 100644 --- a/src/box/tuple_hash.cc +++ b/src/box/tuple_hash.cc @@ -30,7 +30,6 @@ */ #include "tuple_hash.h" - #include "third_party/PMurHash.h" #include "coll.h" diff --git a/src/box/coll.c b/src/coll.c similarity index 63% rename from src/box/coll.c rename to src/coll.c index 436d8d127..66afa6c4f 100644 --- a/src/box/coll.c +++ b/src/coll.c @@ -1,5 +1,5 @@ /* - * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS file. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -31,19 +31,18 @@ #include "coll.h" #include "third_party/PMurHash.h" -#include "error.h" #include "diag.h" #include #include enum { - MAX_HASH_BUFFER = 1024, MAX_LOCALE = 1024, }; -/** - * Compare two string using ICU collation. - */ +static_assert(MAX_LOCALE <= TT_STATIC_BUF_LEN, + "static buf is used to 0-terminate locale name"); + +/** Compare two string using ICU collation. */ static int coll_icu_cmp(const char *s, size_t slen, const char *t, size_t tlen, const struct coll *coll) @@ -66,9 +65,7 @@ coll_icu_cmp(const char *s, size_t slen, const char *t, size_t tlen, return (int)result; } -/** - * Get a hash of a string using ICU collation. - */ +/** Get a hash of a string using ICU collation. */ static uint32_t coll_icu_hash(const char *s, size_t s_len, uint32_t *ph, uint32_t *pcarry, struct coll *coll) @@ -76,115 +73,103 @@ coll_icu_hash(const char *s, size_t s_len, uint32_t *ph, uint32_t *pcarry, uint32_t total_size = 0; UCharIterator itr; uiter_setUTF8(&itr, s, s_len); - uint8_t buf[MAX_HASH_BUFFER]; + uint8_t *buf = (uint8_t *) tt_static_buf(); uint32_t state[2] = {0, 0}; UErrorCode status = U_ZERO_ERROR; - while (true) { - int32_t got = ucol_nextSortKeyPart(coll->icu.collator, - &itr, state, buf, - MAX_HASH_BUFFER, &status); + int32_t got; + do { + got = ucol_nextSortKeyPart(coll->icu.collator, &itr, state, buf, + TT_STATIC_BUF_LEN, &status); PMurHash32_Process(ph, pcarry, buf, got); total_size += got; - if (got < MAX_HASH_BUFFER) - break; - } + } while (got == TT_STATIC_BUF_LEN); return total_size; } /** * Set up ICU collator and init cmp and hash members of collation. - * @param coll - collation to set up. - * @param def - collation definition. - * @return 0 on success, -1 on error. + * @param coll Collation to set up. + * @param def Collation definition. + * @retval 0 Success. + * @retval -1 Collation error. */ static int coll_icu_init_cmp(struct coll *coll, const struct coll_def *def) { - if (coll->icu.collator != NULL) { - ucol_close(coll->icu.collator); - coll->icu.collator = NULL; - } - if (def->locale_len >= MAX_LOCALE) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "too long locale"); + diag_set(CollationError, "too long locale"); return -1; } - char locale[MAX_LOCALE]; + char *locale = tt_static_buf(); memcpy(locale, def->locale, def->locale_len); locale[def->locale_len] = '\0'; UErrorCode status = U_ZERO_ERROR; struct UCollator *collator = ucol_open(locale, &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - u_errorName(status)); + diag_set(CollationError, u_errorName(status)); return -1; } coll->icu.collator = collator; if (def->icu.french_collation != COLL_ICU_DEFAULT) { enum coll_icu_on_off w = def->icu.french_collation; - UColAttributeValue v = - w == COLL_ICU_ON ? UCOL_ON : - w == COLL_ICU_OFF ? UCOL_OFF : - UCOL_DEFAULT; + UColAttributeValue v = w == COLL_ICU_ON ? UCOL_ON : + w == COLL_ICU_OFF ? UCOL_OFF : + UCOL_DEFAULT; ucol_setAttribute(collator, UCOL_FRENCH_COLLATION, v, &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "failed to set french_collation"); + diag_set(CollationError, "failed to set "\ + "french_collation: %s", u_errorName(status)); return -1; } } if (def->icu.alternate_handling != COLL_ICU_AH_DEFAULT) { - enum coll_icu_alternate_handling w = def->icu.alternate_handling; + enum coll_icu_alternate_handling w = + def->icu.alternate_handling; UColAttributeValue v = w == COLL_ICU_AH_NON_IGNORABLE ? UCOL_NON_IGNORABLE : - w == COLL_ICU_AH_SHIFTED ? UCOL_SHIFTED : - UCOL_DEFAULT; - ucol_setAttribute(collator, UCOL_ALTERNATE_HANDLING, v, &status); + w == COLL_ICU_AH_SHIFTED ? UCOL_SHIFTED : UCOL_DEFAULT; + ucol_setAttribute(collator, UCOL_ALTERNATE_HANDLING, v, + &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "failed to set alternate_handling"); + diag_set(CollationError, "failed to set "\ + "alternate_handling: %s", u_errorName(status)); return -1; } } if (def->icu.case_first != COLL_ICU_CF_DEFAULT) { enum coll_icu_case_first w = def->icu.case_first; - UColAttributeValue v = - w == COLL_ICU_CF_OFF ? UCOL_OFF : + UColAttributeValue v = w == COLL_ICU_CF_OFF ? UCOL_OFF : w == COLL_ICU_CF_UPPER_FIRST ? UCOL_UPPER_FIRST : w == COLL_ICU_CF_LOWER_FIRST ? UCOL_LOWER_FIRST : UCOL_DEFAULT; ucol_setAttribute(collator, UCOL_CASE_FIRST, v, &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "failed to set case_first"); + diag_set(CollationError, "failed to set case_first: "\ + "%s", u_errorName(status)); return -1; } } if (def->icu.case_level != COLL_ICU_DEFAULT) { enum coll_icu_on_off w = def->icu.case_level; - UColAttributeValue v = - w == COLL_ICU_ON ? UCOL_ON : - w == COLL_ICU_OFF ? UCOL_OFF : - UCOL_DEFAULT; + UColAttributeValue v = w == COLL_ICU_ON ? UCOL_ON : + w == COLL_ICU_OFF ? UCOL_OFF : UCOL_DEFAULT; ucol_setAttribute(collator, UCOL_CASE_LEVEL , v, &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "failed to set case_level"); + diag_set(CollationError, "failed to set case_level: "\ + "%s", u_errorName(status)); return -1; } } if (def->icu.normalization_mode != COLL_ICU_DEFAULT) { enum coll_icu_on_off w = def->icu.normalization_mode; - UColAttributeValue v = - w == COLL_ICU_ON ? UCOL_ON : - w == COLL_ICU_OFF ? UCOL_OFF : - UCOL_DEFAULT; - ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, v, &status); + UColAttributeValue v = w == COLL_ICU_ON ? UCOL_ON : + w == COLL_ICU_OFF ? UCOL_OFF : UCOL_DEFAULT; + ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, v, + &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "failed to set normalization_mode"); + diag_set(CollationError, "failed to set "\ + "normalization_mode: %s", u_errorName(status)); return -1; } } @@ -199,81 +184,51 @@ coll_icu_init_cmp(struct coll *coll, const struct coll_def *def) UCOL_DEFAULT; ucol_setAttribute(collator, UCOL_STRENGTH, v, &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "failed to set strength"); + diag_set(CollationError, "failed to set strength: %s", + u_errorName(status)); return -1; } } if (def->icu.numeric_collation != COLL_ICU_DEFAULT) { enum coll_icu_on_off w = def->icu.numeric_collation; - UColAttributeValue v = - w == COLL_ICU_ON ? UCOL_ON : - w == COLL_ICU_OFF ? UCOL_OFF : - UCOL_DEFAULT; + UColAttributeValue v = w == COLL_ICU_ON ? UCOL_ON : + w == COLL_ICU_OFF ? UCOL_OFF : UCOL_DEFAULT; ucol_setAttribute(collator, UCOL_NUMERIC_COLLATION, v, &status); if (U_FAILURE(status)) { - diag_set(ClientError, ER_CANT_CREATE_COLLATION, - "failed to set numeric_collation"); + diag_set(CollationError, "failed to set "\ + "numeric_collation: %s", u_errorName(status)); return -1; } } - coll->cmp = coll_icu_cmp; coll->hash = coll_icu_hash; return 0; } -/** - * Destroy ICU collation. - */ -static void -coll_icu_destroy(struct coll *coll) -{ - if (coll->icu.collator != NULL) - ucol_close(coll->icu.collator); -} - -/** - * Create a collation by definition. - * @param def - collation definition. - * @return - the collation OR NULL on memory error (diag is set). - */ struct coll * coll_new(const struct coll_def *def) { - assert(def->type == COLL_TYPE_ICU); /* no more types are implemented yet */ - - size_t total_len = sizeof(struct coll) + def->name_len + 1; - struct coll *coll = (struct coll *)calloc(1, total_len); + assert(def->type == COLL_TYPE_ICU); + struct coll *coll = (struct coll *) malloc(sizeof(*coll)); if (coll == NULL) { - diag_set(OutOfMemory, total_len, "malloc", "struct coll"); + diag_set(OutOfMemory, sizeof(*coll), "malloc", "coll"); return NULL; } - coll->refs = 1; - coll->id = def->id; - coll->owner_id = def->owner_id; coll->type = def->type; - coll->name_len = def->name_len; - memcpy(coll->name, def->name, def->name_len); - coll->name[coll->name_len] = 0; - if (coll_icu_init_cmp(coll, def) != 0) { free(coll); return NULL; } - return coll; } void coll_unref(struct coll *coll) { - /* No more types are implemented yet. */ - assert(coll->type == COLL_TYPE_ICU); assert(coll->refs > 0); if (--coll->refs == 0) { - coll_icu_destroy(coll); + ucol_close(coll->icu.collator); free(coll); } } diff --git a/src/box/coll.h b/src/coll.h similarity index 74% rename from src/box/coll.h rename to src/coll.h index 248500ab4..cc834f446 100644 --- a/src/box/coll.h +++ b/src/coll.h @@ -1,7 +1,7 @@ -#ifndef TARANTOOL_BOX_COLL_H_INCLUDED -#define TARANTOOL_BOX_COLL_H_INCLUDED +#ifndef TARANTOOL_COLL_H_INCLUDED +#define TARANTOOL_COLL_H_INCLUDED /* - * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS file. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -41,17 +41,13 @@ extern "C" { struct coll; -typedef int (*coll_cmp_f)(const char *s, size_t s_len, - const char *t, size_t t_len, - const struct coll *coll); +typedef int (*coll_cmp_f)(const char *s, size_t s_len, const char *t, + size_t t_len, const struct coll *coll); -typedef uint32_t (*coll_hash_f)(const char *s, size_t s_len, - uint32_t *ph, uint32_t *pcarry, - struct coll *coll); +typedef uint32_t (*coll_hash_f)(const char *s, size_t s_len, uint32_t *ph, + uint32_t *pcarry, struct coll *coll); -/** - * ICU collation specific data. - */ +/** ICU collation specific data. */ struct UCollator; struct coll_icu { @@ -59,13 +55,10 @@ struct coll_icu { }; /** - * A collation. + * Collation. It has no unique features like name, id or owner. + * Only functional part - comparator, locale, ICU settings. */ struct coll { - /** Personal ID */ - uint32_t id; - /** Owner ID */ - uint32_t owner_id; /** Collation type. */ enum coll_type type; /** Type specific data. */ @@ -75,15 +68,13 @@ struct coll { coll_hash_f hash; /** Reference counter. */ int refs; - /** Collation name. */ - size_t name_len; - char name[0]; }; /** * Create a collation by definition. - * @param def - collation definition. - * @return - the collation OR NULL on memory error (diag is set). + * @param def Collation definition. + * @retval NULL Collation or memory error. + * @retval not NULL Collation. */ struct coll * coll_new(const struct coll_def *def); @@ -103,4 +94,4 @@ coll_unref(struct coll *coll); } /* extern "C" */ #endif /* defined(__cplusplus) */ -#endif /* TARANTOOL_BOX_COLL_H_INCLUDED */ +#endif /* TARANTOOL_COLL_H_INCLUDED */ diff --git a/src/coll_def.c b/src/coll_def.c new file mode 100644 index 000000000..df58caca8 --- /dev/null +++ b/src/coll_def.c @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS file. + * + * 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 AUTHORS ``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 + * AUTHORS 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 "coll_def.h" + +const char *coll_type_strs[] = { + "ICU" +}; + +const char *coll_icu_on_off_strs[] = { + "DEFAULT", + "ON", + "OFF" +}; + +const char *coll_icu_alternate_handling_strs[] = { + "DEFAULT", + "NON_IGNORABLE", + "SHIFTED" +}; + +const char *coll_icu_case_first_strs[] = { + "DEFAULT", + "OFF", + "UPPER_FIRST", + "LOWER_FIRST" +}; + +const char *coll_icu_strength_strs[] = { + "DEFAULT", + "PRIMARY", + "SECONDARY", + "TERTIARY", + "QUATERNARY", + "IDENTICAL" +}; diff --git a/src/box/coll_def.h b/src/coll_def.h similarity index 82% rename from src/box/coll_def.h rename to src/coll_def.h index 7a1027a1e..10dbc860e 100644 --- a/src/box/coll_def.h +++ b/src/coll_def.h @@ -1,7 +1,7 @@ -#ifndef TARANTOOL_BOX_COLL_DEF_H_INCLUDED -#define TARANTOOL_BOX_COLL_DEF_H_INCLUDED +#ifndef TARANTOOL_COLL_DEF_H_INCLUDED +#define TARANTOOL_COLL_DEF_H_INCLUDED /* - * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file. + * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS file. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following @@ -30,18 +30,10 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - #include #include -#include "opt_def.h" - -#if defined(__cplusplus) -extern "C" { -#endif /* defined(__cplusplus) */ -/** - * The supported collation types - */ +/** The supported collation types */ enum coll_type { COLL_TYPE_ICU = 0, coll_type_MAX, @@ -109,17 +101,8 @@ struct coll_icu_def { enum coll_icu_on_off numeric_collation; }; -/** - * Definition of a collation. - */ +/** Collation definition. */ struct coll_def { - /** Perconal ID */ - uint32_t id; - /** Owner ID */ - uint32_t owner_id; - /** Collation name. */ - size_t name_len; - const char *name; /** Locale. */ size_t locale_len; const char *locale; @@ -129,10 +112,4 @@ struct coll_def { struct coll_icu_def icu; }; -extern const struct opt_def coll_icu_opts_reg[]; - -#if defined(__cplusplus) -} /* extern "C" */ -#endif /* defined(__cplusplus) */ - -#endif /* TARANTOOL_BOX_COLL_DEF_H_INCLUDED */ +#endif /* TARANTOOL_COLL_DEF_H_INCLUDED */ diff --git a/src/diag.h b/src/diag.h index dc6c132d5..bd5a539b0 100644 --- a/src/diag.h +++ b/src/diag.h @@ -249,6 +249,8 @@ struct error * BuildSystemError(const char *file, unsigned line, const char *format, ...); struct error * BuildXlogError(const char *file, unsigned line, const char *format, ...); +struct error * +BuildCollationError(const char *file, unsigned line, const char *format, ...); struct index_def; diff --git a/src/exception.cc b/src/exception.cc index 56077f76d..1cbf8852f 100644 --- a/src/exception.cc +++ b/src/exception.cc @@ -235,6 +235,18 @@ IllegalParams::IllegalParams(const char *file, unsigned line, va_end(ap); } +const struct type_info type_CollationError = + make_type("CollationError", &type_Exception); + +CollationError::CollationError(const char *file, unsigned line, + const char *format, ...) + : Exception(&type_CollationError, file, line) +{ + va_list ap; + va_start(ap, format); + error_vformat_msg(this, format, ap); + va_end(ap); +} #define BuildAlloc(type) \ void *p = malloc(sizeof(type)); \ @@ -303,6 +315,18 @@ BuildSystemError(const char *file, unsigned line, const char *format, ...) return e; } +struct error * +BuildCollationError(const char *file, unsigned line, const char *format, ...) +{ + BuildAlloc(CollationError); + CollationError *e = new (p) CollationError(file, line, ""); + va_list ap; + va_start(ap, format); + error_vformat_msg(e, format, ap); + va_end(ap); + return e; +} + void exception_init() { diff --git a/src/exception.h b/src/exception.h index fe7ab84f0..f56616b68 100644 --- a/src/exception.h +++ b/src/exception.h @@ -49,6 +49,7 @@ extern const struct type_info type_ChannelIsClosed; extern const struct type_info type_LuajitError; extern const struct type_info type_IllegalParams; extern const struct type_info type_SystemError; +extern const struct type_info type_CollationError; const char * exception_get_string(struct error *e, const struct method_info *method); @@ -139,6 +140,14 @@ public: IllegalParams(const char *file, unsigned line, const char *format, ...); virtual void raise() { throw this; } }; + +class CollationError: public Exception { +public: + CollationError(const char *file, unsigned line, const char *format, + ...); + virtual void raise() { throw this; } +}; + /** * Initialize the exception subsystem. */ diff --git a/test/unit/coll.cpp b/test/unit/coll.cpp index d77959606..53e06f2ce 100644 --- a/test/unit/coll.cpp +++ b/test/unit/coll.cpp @@ -1,14 +1,14 @@ -#include "box/coll.h" #include #include #include #include -#include #include #include #include #include #include +#include "coll_def.h" +#include "coll.h" #include "third_party/PMurHash.h" using namespace std; @@ -51,8 +51,6 @@ manual_test() def.locale = "ru_RU"; def.locale_len = strlen(def.locale); def.type = COLL_TYPE_ICU; - def.name = "test"; - def.name_len = strlen(def.name); struct coll *coll; cout << " -- default ru_RU -- " << endl; @@ -136,8 +134,6 @@ hash_test() def.locale = "ru_RU"; def.locale_len = strlen(def.locale); def.type = COLL_TYPE_ICU; - def.name = "test"; - def.name_len = strlen(def.name); struct coll *coll; /* Case sensitive */ -- 2.15.1 (Apple Git-101)