[tarantool-patches] Re: [PATCH v3 2/4] collation: split collation into core and box objects

Vladislav Shpilevoy v.shpilevoy at tarantool.org
Thu May 17 22:23:27 MSK 2018


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 <stddef.h>
+#include <stdint.h>
+
+#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 <stdint.h>
  
  #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 <stddef.h>
+#include <stdint.h>
+#include <coll_def.h>
+#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 <msgpuck.h>
  #include <limits.h>
  #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 <math.h>
-#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 <unicode/ucol.h>
  #include <trivia/config.h>
  
  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 <stddef.h>
  #include <stdint.h>
-#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 <iostream>
  #include <vector>
  #include <algorithm>
  #include <string.h>
-#include <box/coll_def.h>
  #include <assert.h>
  #include <msgpuck.h>
  #include <diag.h>
  #include <fiber.h>
  #include <memory.h>
+#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)





More information about the Tarantool-patches mailing list